买卖股票的最佳时机 文章:32. 买卖股票的最佳时机
题目:121. 买卖股票的最佳时机
【思路】
暴力 找最大间距
1 2 3 4 5 6 7 8 9 func maxProfit (prices []int ) int { res :=0 for i:=0 ;i < len (prices);i++{ for j :=i+1 ; j < len (prices);j++{ res = max(res,prices[j] - prices[i]) } } return res }
贪心 找左边最小值和右边最大值即可。
1 2 3 4 5 6 7 8 9 func maxProfit (prices []int ) int { leftMin := math.MaxInt rightMax :=0 for i :=0 ;i<len (prices);i++{ leftMin = min(leftMin,prices[i]) rightMax = max(rightMax,prices[i]-leftMin) } return rightMax }
动态规划 1.确定dp数组及其下标含义
dp[i] [0]:第i天持有股票所得最多现金
dp[i] [1]:第i天不持有股票所得最多现金
2.确定递推公式
如果第i天持有股票即dp[i] [0],那么可以由两个状态推出来
第i-1天持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i-1] [0]
第i天买入股票,所得现金就是买入今天的股票后所得现金 即:-price[i]
如果第i天不持有股票即dp[i] [1],也可以由两个状态推出来
第i-1天不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i-1] [1]
第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金 即:prices[i] + dp[i-1] [0]
dp[i] [1]取最大的,dp[i] [1] = max(dp[i-1] [i],prices[i] + dp[i-1] [0])
3.数组初始化
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[0] [0]和dp[0] [1]推导出来的。
dp[0] [0]表示第0天持有股票,此时的持有股票一定是买入股票了,因为不可能有前一天退出来,所以dp[0] [0] -= prices[0]
dp[0] [1]表示第0天不持有股票,不持有股票那么现金就是0,所以dp[0] [1]=0
4.确定遍历顺序
从递推公式可以看出dp[i]都是由dp[i-1]推导出来的,那么一定是从前向后遍历
5.举例推导。。(上边不理解的话可以画图看看,就能理解了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public int maxProfit (int [] prices) { int len = prices.length; if (len == 0 )return 0 ; int [][]dp = new int [len][2 ]; dp[0 ][0 ] = -prices[0 ]; for (int i = 1 ; i < prices.length;i++){ dp[i][0 ] = Math.max(dp[i-1 ][0 ],-prices[i]); dp[i][1 ] = Math.max(dp[i-1 ][1 ],prices[i]+dp[i-1 ][0 ]); } return dp[len-1 ][1 ]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 func maxProfit (prices []int ) int { dp := make ([][]int ,len (prices)) for i:=0 ;i<len (dp);i++{ dp[i] = make ([]int ,2 ) } dp[0 ][0 ] = -prices[0 ] dp[0 ][1 ] = 0 for i :=1 ; i< len (prices);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]) } return dp[len (dp)-1 ][1 ] }
买卖股票的最佳时机II 文章:34. 买卖股票的最佳时机II
题目:122. 买卖股票的最佳时机 II
【思路】
和上题的区别在于是本题需要完成多次买卖 !
意味着我们需要在递推公式的持股公式 进行修改。
第i天持有股票 即dp[i] [0],如果第i天买入股票,所得现金就是昨天不持有股票的所得现金 减去 今天的股票价格 即:dp[i] [0] = dp[i-1] [1] - prices[i]
1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int maxProfit (int [] prices) { int [][] dp = new int [prices.length][2 ]; dp[0 ][0 ] = -prices[0 ]; dp[0 ][1 ] = 0 ; for (int i= 1 ;i < prices.length;i++){ dp[i][0 ] = Math.max(dp[i-1 ][1 ] - prices[i], dp[i-1 ][0 ]); dp[i][1 ] = Math.max(dp[i-1 ][1 ],dp[i-1 ][0 ] + prices[i]); } return dp[dp.length-1 ][1 ]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 func maxProfit (prices []int ) int { dp := make ([][]int ,len (prices)) for i := 0 ; i < len (dp);i++{ dp[i] = make ([]int ,2 ) } dp[0 ][0 ] = -prices[0 ] dp[0 ][1 ] = 0 for i :=1 ; i < len (dp);i++{ dp[i][0 ] = max(dp[i-1 ][0 ], dp[i-1 ][1 ] - prices[i]) dp[i][1 ] = max(dp[i-1 ][1 ] , dp[i-1 ][0 ] + prices[i]) } return dp[len (prices)-1 ][1 ] }
【算法总结】
股票问题:买入卖出、持有和不持有的状态下需要区分。
买卖股票的最佳时期II:可以多次买卖,因此dp[i] [0]的推导公式需要注意是从前一状态不持有股票的情况下 /与前一状态持有股票保持不变的情况下 取最大值得出。