122. Best Time to Buy and Sell Stock II(交易次数无限)
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).
Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).
Example 1:
Input: [7,1,5,3,6,4] Output: 7 Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Example 2:
Input: [1,2,3,4,5] Output: 4 Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.
Example 3:
Input: [7,6,4,3,1] Output: 0 Explanation: In this case, no transaction is done, i.e. max profit = 0.
1 动态规划
class Solution { public: int maxProfit(vector<int>& prices) { int n = prices.size(); vector<vector<int>> dp = vector<vector<int>>(n,vector<int>(2,0)); //dp[i][j]:下标为 i 这一天结束的时候,手上持股状态为 j 时(0/1),我们持有的现金数 //买入股票手上的现金数减少,卖出股票手上的现金数增加 dp[0][0] = 0; dp[0][1] = -prices[0]; for(int i = 1;i < n;i++) { // 今天没有持有 = 【昨天没持有】 【昨天持有了,今天卖掉】 dp[i][0] = max(dp[i-1][0],prices[i]+dp[i-1][1]); // 今天持有 = 【昨天没持有,今天买入,只有1次买入机会】, 【昨天持有】 //dp[i][1] = max(-prices[i], dp[i-1][1]); //今天持有 = 【昨天没持有,今天买入,无数次买入机会】, 【昨天持有】 dp[i][1] = max(dp[i-1][0]-prices[i], dp[i-1][1]); } return dp[n-1][0]; } };
方法2:贪心算法(针对这道问题的特殊解法)
贪心算法的直觉:由于不限制交易次数,只要今天股价比昨天高,就交易。
下面对这个算法进行几点说明:
该算法仅可以用于计算,但 计算的过程并不是真正交易的过程,但可以用贪心算法计算题目要求的最大利润。下面说明等价性:以 [1, 2, 3, 4] 为例,这 4 天的股价依次上升,按照贪心算法,得到的最大利润是:
res = (prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])
= prices[3] - prices[0]
仔细观察上面的式子,按照贪心算法,在下标为 1、2、3 的这三天,我们做的操作应该是买进昨天的,卖出今天的,虽然这种操作题目并不允许,但是它等价于:在下标为 0 的那一天买入,在下标为 3 的那一天卖出。
为什么叫「贪心算法」
回到贪心算法的定义:(下面是来自《算法导论(第三版)》第 16 章的叙述)
贪心算法 在每一步总是做出在当前看来最好的选择。
「贪心算法」 和 「动态规划」、「回溯搜索」 算法一样,完成一件事情,是 分步决策 的;
「贪心算法」 在每一步总是做出在当前看来最好的选择,我是这样理解 「最好」 这两个字的意思:
「最好」 的意思往往根据题目而来,可能是 「最小」,也可能是 「最大」;
贪心算法和动态规划相比,它既不看前面(也就是说它不需要从前面的状态转移过来),也不看后面(无后效性,后面的选择不会对前面的选择有影响),因此贪心算法时间复杂度一般是线性的,空间复杂度是常数级别的;
这道题 「贪心」 的地方在于,对于 「今天的股价 - 昨天的股价」,得到的结果有 3 种可能:① 正数,② 00,③负数。贪心算法的决策是: 只加正数 。
class Solution { public: int maxProfit(vector<int>& prices) { if (prices.size()<2) return 0; int cur_gain = 0; for(int i = 1; i < prices.size(); i++) { cur_gain += max(0,prices[i]-prices[i-1]); } return cur_gain; } };
其实,就是把所有的递增区间加起来。