一.买卖股票第一形态,第一道题是在剑指offer上出现过的面试题63股票的最大利润,此时给出了股票价格的数组要求买卖一次能收获的最大利润。
prices[9,11,8,5,7,12,16,14]
dp[0,02,2,2,2,07,11,11]
方法就是动态规划,用空间换时间,建立一个同等大小的dp数组,递推公式:
前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格}
二.买卖股票第二形态,给出了股票价格的数,你可以尽可能地完成更多的交易,你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票) 求获得的最大利益。
思想是贪心算法,今天比明天赚就买入,很多人容易想复杂最后发现是个脑经急转弯
我感觉可能很多人在考虑买入卖出时间可能间隔多天,但是多天也是几个两个组合起来的不是
三.买卖股票第三形态,此时给出了股票价格的数组,要求你最多可以完成 两笔 交易,计算你所能获取的最大利润。
思想回到第一形态的动态规划,用同样一个dp数组存储前i天的最大收益
例子:prices[3,3,5,0,0,3,1,4]
dp[0,0,0,2,2,2,3,3,4]
分析一下res=max(res,dp[j]+prices[i-1]-prices[j-1])是什么意思
i=2 res=max(res,dp[1]+prices[1]-prices[0])
i=3 res=max(res,dp[2]+prices[2]-prices[1],p[1]+prices[2]-prices[0])
i=4 res=max(res,dp[3]+prices[3]-prices[2],dp[2]+prices[3]-prices[1],dp[1]+prices[3]-prices[0])
i=5 res=max(res,dp[4]+prices[4]-prices[3],dp[3]+prices[4]-prices[2],dp[2]+prices[4]-prices[1],dp[1]+prices[4]-prices[0])
i=6 res=max(res,dp[5]+prices[5]-prices[4],dp[4]+prices[5]-prices[4],dp[3]+prices[5]-prices[2],dp[2]+prices[5]-prices[1],dp[1]+prices[5]-prices[0])
慢慢规律应该出来了,就是穷举的思想,其实动态规划本质还是穷举,在穷举的基础上做出了一些优化,在这道题的体现就是我们不会穷举所有情况而是prices[i-1]>prices[i-2]就是有新的收益情况的时候重新穷举看能不能打破原来的收益极限。并且我们用了dp数组去存储前i天的最大收益,避免了重复计算已经计算过的步骤。
在给出的例子中只有i=3,6,8的时候会进入穷举,其他情况都直接dp[i]=dp[i-1]解决了。
四.终极形态,此时给出了股票价格的数组,要求你最多可以完成 两笔 交易,计算你所能获取的最大利润。
这个道题难在把之前三道题的考点结合起来了,既有贪心的思想也有动态规划还要分情况讨论。
这个分情况就很哲学,就是什么情况下这道题会从动态规划退化为贪心算法。
prices.size()/2<=k,这是会退化为贪心,因为此时相当于不限制交易次数,prices最多需要交易prices.size()/2次,比如[1,3,2,4,3,6]这样才需要交易三次。你可以尝试举例不会超过三次。在prices.size()/2>k时,需要从prices.size()/2中选择k次交易组成最大利润。
由于这道题有点难,我还是暴力穷举找思路,怎么选择出k个交易。以[1,3,2,4,3,6],k=3为例。
p=prices[0]=1时,buyArr[-100,-100,-100,-100] sellArr[0,0,0,0]
buyArr[1]=max(buyArr[1],sellArr[0]-prices[0])=max(-100,0-1)=-1;
sellArr[1]=max(sellArr[1],buyArr[1]+prices[0])=max(0,-1+1)=0;
buyArr[2]=max(buyArr[2],sellArr[1]-prices[0])=max(-100,0-1)=-1;
sellArr[2]=max(sellArr[2],buyArr[2]+prices[0])=max(0,-1+1)=0;
buyArr[3]=max(buyArr[3],sellArr[2]-prices[0])=max(-100,0-1)=-1;
sellArr[3]=max(sellArr[3],buyArr[3]+prices[0])=max(0,-1+1)=0;
p=prices[1]=3时,buyArr[-100,-1,-1,-1] sellArr[0,0,0,0]
buyArr[1]=max(buyArr[1],sellArr[0]-p)=max(-1,0-3)=-1;
sellArr[1]=max(sellArr[1],buyArr[1]+prices[1])=max(0,-1+3)=2;
buyArr[2]=max(buyArr[2],sellArr[1]-p)=max(-1,2-3)=-1;
sellArr[2]=max(sellArr[2],buyArr[2]+p)=max(2,-1+3)=2;
buyArr[3]=max(buyArr[3],sellArr[2]-p)=max(-1,2-3)=-1;
sellArr[3]=max(sellArr[3],buyArr[3]+p)=max(0,-1+3)=2;
p=prices[2]=2时,buyArr[-1,-1,-1] sellArr[2,2,2]
buyArr[1]=max(buyArr[1],sell[0]-p)=max(-1,0-2)=-1;
sellArr[1]=max(sellArr[1],buyArr[1]+p)=max(2,-1+2)=2;
buyArr[2]=max(buyArr[2],sellArr[1]-prices[2])=max(-1,2-2)=0;
sellArr[2]=max(sellArr[2],buyArr[2]+p)=max(2,0+2)=2;
buyArr[3]=max(buyArr[3],sellArr[2]-prices[2])=max(-1,2-2)=0;
sellArr[3]=max(sellArr[3],buyArr[3]+p)=max(2,0+2)=2;
p=prices[3]=4时,buyArr[-100,-1,0,0] sellArr[0,2,2,2]
buyArr[1]=max(buyArr[1],sell[0]-p)=max(-1,0-4)=-1;
sellArr[1]=max(sellArr[1],buyArr[1]+prices[3])=max(2,-1+4)=3;
buyArr[2]=max(buyArr[2],sellArr[1]-p)=max(0,3-4)=0;
sellArr[2]=max(sellArr[2],buyArr[2]+prices[3])=max(2,0+4)=4;
buyArr[3]=max(buyArr[3],sellArr[2]-p)=max(0,4-4)=0;
sellArr[3]=max(sellArr[3],buyArr[3]+prices[3])=max(2,0+4)=4;
buyArr[-100,-1,0,0] sellArr[0,3,4,4]
这样慢慢找出一点规律就会发现sellArr[3]就是我们要求的最大利润,而sellArr[3]靠buyArr[3]推倒,buyArr[3]靠sellArr[2]推倒......sellArr[i]依靠buyArr[i],buyArr[i]依靠sellArr[i-1]有种递归的感觉。如果你观察sellArr[3]的演变过程应该就是买入1卖出3买入2卖出4买入3卖出5的过程。退化成贪心时时间复杂度为O(N),动态规划时时间复杂度为O(KN)。