import java.util.*; public class Stock { public int maxProfit(int[] prices, int n) { // return solution1(prices, n); // return solution2(prices, n); return solution3(prices, n); } /** * 动态规划: 状态机 * * 两次交易同时开始 * * dp[i][0]表示股票前i种价格第一次交易买入后所得收益 * dp[i][1]表示股票前i种价格第一次交易卖出后所得收益 * dp[i][2]表示股票前i种价格第二次交易买入后所得收益 * dp[i][3]表示股票前i种价格第二次交易卖出后所得收益 * * 四种状态: * 第一次交易买入: 要么是之前买的, 要么是今天买的 * 第一次交易卖出: 要么是之前卖的, 要么是今天卖的 * 第二次交易买入: 要么是之前买的, 要么是今天买的 * 第二次交易卖出: 要么是之前卖的, 要么是今天卖的 * * 分别对应关系式: * dp[i][0] = max(dp[i-1][0], -prices[i]) * dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]) * dp[i][2] = max(dp[i-1][2], dp[i-1][1]-prices[i]) * dp[i][3] = max(dp[i-1][3], dp[i-1][2]+prices[i]) * * @param prices * @param n * @return */ private int solution1(int[] prices, int n){ int[][] dp = new int[n][4]; // 一次买入 dp[0][0] = -prices[0]; // 一次卖出 dp[0][1] = 0; // 二次买入 dp[0][2] = -prices[0]; // 二次卖出 dp[0][3] = 0; for(int i=1; i<n; i++){ dp[i][0] = Math.max(dp[i-1][0], -prices[i]); dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+prices[i]); dp[i][2] = Math.max(dp[i-1][2], dp[i-1][1]-prices[i]); dp[i][3] = Math.max(dp[i-1][3], dp[i-1][2]+prices[i]); } return dp[n-1][3]; } /** * 动态规划: 状态机 * * 两次交易同时开始 * * buy1 表示股票前i种价格第一次交易买入后所得收益 * sell1 表示股票前i种价格第一次交易卖出后所得收益 * buy2 表示股票前i种价格第二次交易买入后所得收益 * sell2 表示股票前i种价格第二次交易卖出后所得收益 * * 四种状态: * 第一次交易买入: 要么是之前买的, 要么是今天买的 * 第一次交易卖出: 要么是之前卖的, 要么是今天卖的 * 第二次交易买入: 要么是之前买的, 要么是今天买的 * 第二次交易卖出: 要么是之前卖的, 要么是今天卖的 * * 分别对应关系式: * buy1 = max(buy1, -prices[i]) * sell1 = max(sell1, buy1+prices[i]) * buy2 = max(buy2, sell1-prices[i]) * sell2 = max(sell2, buy2+prices[i]) * * @param prices * @param n * @return */ private int solution2(int[] prices, int n){ // 一次买入 int buy1 = -prices[0]; // 一次卖出 int sell1 = 0; // 二次买入 int buy2 = -prices[0]; // 二次卖出 int sell2 = 0; for(int i=1; i<n; i++){ buy1 = Math.max(buy1, -prices[i]); sell1 = Math.max(sell1, buy1+prices[i]); buy2 = Math.max(buy2, sell1-prices[i]); sell2 = Math.max(sell2, buy2+prices[i]); } return sell2; } /** * 动态规划: 双向 * @param prices * @param n * @return */ private int solution3(int[] prices, int n){ int[] left = new int[n]; int[] right = new int[n]; int leftMin = prices[0]; int rightMax = prices[n-1]; int sum = 0; // 左段一次交易最大收益 for(int i=1; i<n; i++){ leftMin = Math.min(prices[i], leftMin); left[i] = Math.max(prices[i]-leftMin, left[i-1]); } // 右段一次交易最大收益 for(int i=n-2 ; i>=0; i--){ rightMax = Math.max(prices[i], rightMax); right[i] = Math.max(rightMax-prices[i], right[i+1]); } // 两次交易最大收益 for(int i=0 ; i<n; i++){ sum = Math.max(sum, left[i]+right[i]); } return sum; } }