动态规划之股票问题
坚持写博客也是一件挺难的事情……
一次交易问题
问题描述:
假如你有一个数组,其中第i个元素是股票在第i天的价格,你有一次买入和卖出的机会。(只有买入了股票后才可以卖出)。请你设计一个算法来计算可以获得最大的收益。
示例1:
输入:[1、3、4]
输出:3
解法一
我们应该很快就有一个解题思路,这题就是让我们对这个数组的元素按照顺序进行减操作,然后要求得到最大的结果。毋庸置疑我们可以用冒泡的思想,将每个元素的都进行一次减操作,然后得到结果。具体代码如下:
int maxProfit(vector<int>& prices) {
// write code here
//冒泡排序
int len = prices.size();
int max = 0;
for(int i=0;i<len-1;i++)
{
for(int j=i+1;j<len;j++)
{
if(prices[j] - prices[i] > max)
{
max = prices[j] - prices[i];
}
}
}
return max;
}
解法二:
上面的解法很轻易的我们就能想到,但是它的时间复杂度是O(n2)。那么我们有没有办法在节省时间呢?接下来我们用O(n)的时间复杂度尝试解决问题。
每一天我们对股票的操作只有两个状态:1、当天买入股票需要的最小花费。2、当天卖出股票的最大收益。于是乎,
我们可以定义一个dp二维数组用来描述每一天的状态。其中规定:dp[i][0]:代表第i天买入股票需要花费的最小值,dp[i][1]:代表第i天卖出股票的最大收益。然后我们可计算出相关的转移方程:
第一天的时候,我们只能买入,没有办法卖出。所以
dp[0][0] = prices[0],dp[0][1] = 0;
第i天的时候:
dp[i][0] = min(dp[i-1][0],prices[i]);//买入股票最小花费。
dp[i][1] = max(dp[i-1][1],prices[i]- dp[i-1][0]);//卖出股票的最大收益
完整的代码:
int maxProfit(vector<int>& prices) {
// write code here
int len = prices.size();
if(len == 0) return 0;
int dp[len][2];
dp[0][0] = prices[0];
dp[0][1] = 0;
for(int i=1;i<len;++i)
{
dp[i][0] = min(dp[i-1][0],prices[i]);
dp[i][1] = max(dp[i-1][1],prices[i] - dp[i-1][0]);
}
return dp[len-1][1];
}
两次交易
题目描述:
假定你知道某只股票每一天价格的变动。你最多可以同时持有一只股票。但你最多只能进行两次交易(一次买进和一次卖出记为一次交易。买进和卖出均无手续费)。请设计一个函数,计算你所能获得的最大收益。
示例:
输入:[8,9,3,5,1,3]
输出:4
输出解释:第三天买入,第四天卖出。第五天买入,第六天卖出。
仅仅只是多了一次交易,但是题目的难度却不止上升一倍。我们需要同时知道在每一天每一次买入卖出的实际情况。记录每一天的所有状态。而,每一天的状态其实就5类。分别是:
1、没有做任何交易。
2、第一次买入股票最小花费。
3、第一次卖出股票最大收益。
4、第二次买入股票最小花费。
3、第二次卖出股票最大收益。
当然我们可以定义一个dp[][5]来记录每一天股票交易的状态。计算得到的转移方程如下:
首先,仍然是第一天的时候,只可以买入,不可以卖出。对dp[0][]进行初始化:
dp[0][0] = 0;
dp[0][1] = prices-[0];
dp[0][2] = 0;
dp[0][3] = -prices[0];
dp[0][4] = 0;
第i天的操作:
dp[i][0] = dp[i-1][0];
dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i]);
dp[i][2] = max(dp[i-1][2],prices[i] - dp[i-1][1]);
dp[i][3] = max(dp[i-1][3],dp[i][2] - prices[i]);
dp[i][4] = max(dp[i-1][4],prices[i] - dp[i-1][3]);
完整的代码:
int maxProfit(vector<int>& prices) {
// write code here
//二次交易
int len = prices.size();//获得天数
if(len == 0) return 0;
int dp[len][5];//规划数组,代表每一个状态
//dp[i][0]--->代表第i天没有做任何操作的最大收益
//dp[i][1]--->代表第i天买入第一次股票的最大收益
//dp[i][2]--->代表第i天卖出第一次股票的最大收益
//dp[i][3]--->代表第i天买入第二次股票的最大收益
//dp[i][4]--->代表第i天卖出第一次股票的最大收益
//于是用了动态规划
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0;
dp[0][3] = -prices[0];
dp[0][4] = 0;
for(int i = 1;i<len;++i)
{
dp[i][0] = dp[i-1][0];//这个就像一个装饰
dp[i][1] = max(dp[i-1][1],dp[i][0] - prices[i]);//获得第一次买入股票的最小值
dp[i][2] = max(dp[i-1][2],prices[i] + dp[i-1][1]);//获得第一次卖出股票的最大值
dp[i][3] = max(dp[i-1][3],dp[i][2]-prices[i]);//获得第二次买入股票的最小消费
dp[i][4] = max(dp[i-1][4],prices[i] + dp[i-1][3]);
}
return dp[len-1][4];
}
n次交易
题目描述:
假定你知道某只股票每一天价格的变动。你最多可以同时持有一只股票。但你可以无限次的交易(买进和卖出均无手续费)。请设计一个函数,计算你所能获得的最大收益。
虽然是N次交易,但是它的解题就非常简单,只要prices[i] - prices[i-1] > 就可以加入到总收益当中。代码如下:
int maxProfit(vector<int>& prices) {
// write code here
int res = 0;//代表最终收益
for(int i= 1;i < prices.size();i ++){
int temp = prices[i]-prices[i-1];//收益
if(temp > 0) res += temp;//如果为正收益就加和
}
return res;
}
以上就是股票交易的问题解法,记录出来希望可以帮助到需要的人,也让自己下次不会出错。