[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 题目:一个数组表示一支股票的价格变换. ...
随机推荐
- 1.编译azkaban
1.下载azkaban的源码 https://github.com/azkaban/azkaban.git 然后解压得到azkaban-master.zip,解压:unzip azkaban-mast ...
- 阿里校招内推C++岗位编程题第一题 空格最少的字符串
给定一个字符串S和有效单词的字典D,请确定可以插入到S中的最小空格数,使得最终的字符串完全由D中的有效单词组成.并输出解. 如果没有解则应该输出n/a 例如: 输入: S = “ilikealibab ...
- Keil ARM-CM3 printf输出调试信息到Debug (printf) Viewer
参考资料:http://www.keil.com/support/man/docs/jlink/jlink_trace_itm_viewer.htm 1.Target Options -> De ...
- POJ 3028 Shoot-out(概率DP)
Description This is back in the Wild West where everybody is fighting everybody. In particular, ther ...
- vue移动音乐app开发学习(三):轮播图组件的开发
本系列文章是为了记录学习中的知识点,便于后期自己观看.如果有需要的同学请登录慕课网,找到Vue 2.0 高级实战-开发移动端音乐WebApp进行观看,传送门. 完成后的页面状态以及项目结构如下: 一: ...
- css重修之书(一):如何用css制作比1px更细的边框
如何用css制作比1px更细的边框 在项目的开发过程中,我们常常会使用到border:1px solid xxx,来对元素添加边框: 可是1px的border看起来还是粗了一些粗,不美观,那么有什么方 ...
- html+css基础 - 个人备忘录
//======================html部分===================// 表现内容<meta http-equiv="Content-Type" ...
- lintcode-148-颜色分类
148-颜色分类 给定一个包含红,白,蓝且长度为 n 的数组,将数组元素进行分类使相同颜色的元素相邻,并按照红.白.蓝的顺序进行排序. 我们可以使用整数 0,1 和 2 分别代表红,白,蓝. 注意事项 ...
- OSG数学基础:坐标系统
坐标系是一个精确定位对象位置的框架,所有的图形变换都是基于一定的坐标系进行的. 三维坐标系总体上可以分为两大类:左手坐标系和右手坐标系. 常用的坐标系:世界坐标系.物体坐标系和摄像机坐标系. 世界坐标 ...
- 【beta】Scrum站立会议第1次....11.3
beta阶段,我们nice!团队将进行为期两周的冲刺,Scrum站立会议10次. 小组名称:nice! 组长:李权 成员:于淼 刘芳芳韩媛媛 宫丽君 项目内容:约跑app(约吧) 时间:2016.1 ...