[LeetCode] 递推思想的美妙 Best Time to Buy and Sell Stock I, II, III O(n) 解法
题记:在求最大最小值的类似题目中,递推思想的奇妙之处,在于递推过程也就是比较求值的过程,从而做到一次遍历得到结果。
LeetCode 上面的这三道题最能展现递推思想的美丽之处了。
题1 Best Time to Buy and Sell Stock
Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.
分析:
我们已经知道股票每天的价格,求一次买卖的最大收益。
怎么解?最大值减最小值?肯定不行,因为买必须在卖之前。
简单的递推思想就可以解决
对于1-n天的价格序列,假设maxProfit[i] (0 < i < n)表示第i天卖出时,所获得的最大收益。那么我们要求的值其实就是数组maxProfit[n] n个元素中的最大值。
那么maxProfit[i]如何求?因为卖的天已经确定,所以只要算出1到i 天 中哪一天价格最低,作为买的时间即可。
根据递推思想,要求1到i 天 中哪一天价格最低,我们只需要比较 price[i] 和 1到i-1天内的最低价格,然后取较小值即可。
同样,最后的结果是求maxProfit[n]中的值,我们也可以把求最大值的过程放到遍历中,每次求出 maxProfit[i],我们将它和 maxProfit[0]到maxProfit[i-1] 中选出的最大值max比较,然后更新max即可。
因为比较的过程被放到了遍历的过程中,所以虽然使用递推思想,但是一次遍历就可以实现这个思想。
代码:
class Solution {
public:
int maxProfit(vector<int> &prices) {
if(prices.size() == ) return ;
int maxPrifit = -; //存储最大利润
int min = ; //存储最小价格
vector<int>::iterator i = prices.begin();
vector<int>::iterator end = prices.end();
for(; i < end; ++i){
if(min > (*i)) min = (*i);
if(maxPrifit < ((*i) - min))
maxPrifit = ((*i) - min);
}
return maxPrifit;
}
};
题2 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 (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
分析:
更改的地方是可以多次买卖,但是买必须在卖前。
其实这道题才是三题中最简单的一道。
思路就是“逢涨就买,逢跌就卖”。炒股的最基本道理,只有在已经知道所有股票价格的前提下才能精确地实现这句话 ==
代码:
class Solution {
public:
int maxProfit(vector<int> &prices) {
if(prices.size() <= ) return ;
int buy = -; int profit = ;
vector<int>::iterator i = prices.begin();
vector<int>::iterator end = prices.end();
for(;i != end; ++i){
if((i+) != end && *(i+) > *i && buy < ) buy = (*i);
if(((i+) == end || *(i+) < *i) && buy >= ){
profit += (*i - buy);
buy = -;
}
}
return profit;
}
};
题3 Best Time to Buy and Sell Stock III
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 at most two transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
分析:
题1的变种,可以买卖两次,但是不能重叠。
我的第一反应自然是分而治之,i = 1 to n,然后分别循环计算prices[1~ i], prices[i ~n] 的最大利润,相加,求出和的最大值。时间复杂度是实打实的 O(n2)。
稍微改进一些,就是我们在计算prices[1~ i]的时候,可以使用递推,这样思路就成了,在题1的代码基础上,每次算完prices[1~ i]的最小值,紧接着用一个循环 计算prices[i ~n] 的最大值。这样prices[1~ i]的最大利润计算和 i = 1~n的迭代合并,只有一个子循环, 一定程度上减小时间复杂度,时间复杂度成了 (n-1) + (n-2) + .. + 1,但依然是 O(n2)
实际上可以将复杂度减小到 O(n),这种方法会需要额外的 O(n)空间,但在一般编程领域,如果O(n)的空间能换来时间上减小一个数量级,还是相当好的。
我们先考虑一次买卖prices[1 ~ i] (0 < i < n)的最大利润,这就和题1一样,所不同的是,我们将值存入 firstMaxPro数组,而不是求出总的最大利润。
注意这里的firstMaxPro[n]数组和题目1中maxProfit[n]数组功能是不一样的。maxProfit[i] 表示一定在 i 天卖出的前提下,1~i天的最大利润。firstMaxPro[i]表示1~i天的最大利润,卖出可以在1~i天的任何时候。
接着,我们再做一次遍历,这一次遍历,从n 到 1,为的是将第二次买卖考虑进去,在求第二次买卖的最大利润的同时,就可以加上 firstMaxPro[n]中的对应值,然后求出总和最大。返回这个最大的总和即可。
两次n循环,时间复杂度O(n)
代码:
class Solution {
public:
int maxProfit(vector<int> &prices) {
if(prices.size() <= ) return ;
int* firstMaxPro = new int[prices.size()];
int curMin = ;
int curMaxPro = -;
for(int i = ; i < prices.size(); ++i){
if(curMin > prices[i]) curMin = prices[i];
if(curMaxPro < (prices[i] - curMin)){
curMaxPro = (prices[i] - curMin);
}
firstMaxPro[i] = curMaxPro;
}
//从尾到头遍历
int MaxPro = -; //总的最大利润
int curMax = -; //第二段区间上的最大价格
for(int j = prices.size()-; j >= ; --j){
if(curMax < prices[j]) curMax = prices[j];//第二次买卖的最大利润就等于curMax - prices[j]
if(MaxPro < (firstMaxPro[j] + curMax - prices[j])){
MaxPro = (firstMaxPro[j] + curMax - prices[j]);
}
}
return (MaxPro > ? MaxPro : );
}
};
结语
这三道题其实都不难,都是递推思想的一些演变。但是这三道题可以很典型地体现递推的核心思想和其优势:将比较和择优的过程和递推过程合并,从而只需要单次遍历,在O(n)内获得结果。
[LeetCode] 递推思想的美妙 Best Time to Buy and Sell Stock I, II, III O(n) 解法的更多相关文章
- LeetCode之“动态规划”:Best Time to Buy and Sell Stock I && II && III && IV
Best Time to Buy and Sell Stock I 题目链接 题目要求: Say you have an array for which the ith element is the ...
- LeetCode:Best Time to Buy and Sell Stock I II III
LeetCode:Best Time to Buy and Sell Stock Say you have an array for which the ith element is the pric ...
- leetcode day6 -- String to Integer (atoi) && Best Time to Buy and Sell Stock I II III
1. String to Integer (atoi) Implement atoi to convert a string to an integer. Hint: Carefully con ...
- [Leetcode][JAVA] Best Time to Buy and Sell Stock I, II, III
Best Time to Buy and Sell Stock Say you have an array for which the ith element is the price of a gi ...
- Best Time to Buy and Sell Stock I,II,III [leetcode]
Best Time to Buy and Sell Stock I 你只能一个操作:维修preMin拍摄前最少发生值 代码例如以下: int maxProfit(vector<int> & ...
- [LeetCode]题解(python):123-Best Time to Buy and Sell Stock III
题目来源: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ 题意分析: 和上题类似,array[i]代表第i天物品 ...
- [LeetCode]题解(python):122-Best Time to Buy and Sell Stock II
题目来源: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ 题意分析: 和上题类似,给定array,代表第i天物品i ...
- [LeetCode]题解(python):121-Best Time to Buy and Sell Stock
题目来源: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 题意分析: 给定一个数组,代表array[i] 代表第i天的价 ...
- [leetcode]_Best Time to Buy and Sell Stock I && II
一个系列三道题,我都不会做,google之答案.过了两道,第三道看不懂,放置,稍后继续. 一.Best Time to Buy and Sell Stock I 题目:一个数组表示一支股票的价格变换. ...
随机推荐
- solidity合约详解
Solidity 是一个面向合约的高级语言,其语法类似于JavaScript .是运行在以太坊虚拟机中的代码.这里我们用的是remix编译环境.是一个在线的编译环境.地址为http://remix.e ...
- hadoop问题集(1)
参考: http://dataunion.org/22887.html 1.mapreduce_shuffle does not exist 执行任何时报错: Container launch ...
- 如何做好FAE工作及FAE职位发展
此文较长,是作者对于半导体FAE职业的一些总结,码字不容易,耐心的阅读,欢迎点赞. 曾经认识一位做电源研发的工程师,转行在一家代理商做FAE,做了一年半以后,就提出了离职请求,他老板问他是什么原因,他 ...
- 基于范围的for语句
一.关键点 1. 作用过程 遍历给定序列中的每个元素并对序列中的每个值执行某种操作. 2. 若要修改序列中元素的值,需将类型定义为引用 string s("Hello World!!!&qu ...
- “Hello world!”团队第一周贡献分分配结果
小组名称:Hello World! 项目名称:空天猎 组长:陈建宇 成员:刘成志.阚博文.刘淑霞.黄泽宇.方铭.贾男男 第一周贡献分分配结果 基础分 会议分 提功能分 个人表现分 各项总分 最终分 ...
- 重构 之 总结代码的坏味道 Bad Smell (一) 重复代码 过长函数 过大的类 过长参数列 发散式变化 霰弹式修改
膜拜下 Martin Fowler 大神 , 开始学习 圣经 重构-改善既有代码设计 . 代码的坏味道就意味着需要重构, 对代码的坏味道了然于心是重构的比要前提; . 作者 : 万境绝尘 转载请注明出 ...
- P4编程环境搭建遇到的问题与解决方法
在经历了无数的折腾之后,算是折腾,最后采用的是陈翔学长的脚本加上可爱的shell调整装好的. 链接:p4Install 也许是ubuntu18.04的问题,也有可能是我自己把这个系统折腾的有点杂乱的原 ...
- 浏览器中event.srcElement和event.target的兼容性问题
在IE下,event对象有srcElement属性,但是没有target属性:Firefox下,even对象有target属性,但是没有srcElement属性.. 解决方法:使用obj(obj = ...
- LintCode-112.删除排序链表中的重复元素
删除排序链表中的重复元素 给定一个排序链表,删除所有重复的元素每个元素只留下一个. 样例 给出 1->1->2->null,返回 1->2->null 给出 1-> ...
- 解决XAMPP中,MYSQL因修改my.ini后,无法启动的问题
论这世上谁最娇贵,不是每年只开七天的睡火莲,也不是瑞典的维多利亚公主,更不是一到冬天就自动关机的iPhone 6s, 这世上最娇贵的,非XAMPP中的mysql莫属,记得儿时的我,年少轻狂,当时因为m ...