最近写了恒生电子的笔试,故在此记录.....
题目:股票
题目大概是:
给定一个数组prices,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
其中本金M为10000元,给定股票价格的7天变化即prices数组:[1.0,2.0,1.0,2.0,2.0,3.0,2.0](这里开始与leetcode上的股票题不一样了)求出最大利润。
思路:这题我使用动态规划的思路。
第一步:定义dp数组的意义:
其中dp[i][0]我定义为第i天所持有的股票数,dp[i][1]定义为第i天不持有股票时所能获得的现金数。
第二步:确定递归公式:
dp[i][0] =max(dp[i-1][0],dp[i-1][1]/prices[i]);这样做可以保证在变化的股市里能拿到最值得的股票数。其中dp[i-1][0]就是第i-1天我手中的股票数,dp[i-1][1]/prices[i]表示的就是我第i-1天不持有股票时的现金数去除当天的股价就可以得到股票数。通俗来讲就是我用现在的钱去买现在股市的股票是不是能获得更多,比我之前握在手中不卖会不会更值。
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0]*prices[i]);要么就是延续之前的状态即dp[i-1][1],要么就是将前一天手中的股票给卖了(dp[i - 1][0]*prices[i]),两个求较大值。
第三步:初始化dp[][]数组:
其中两个状态分别是初始时的股票数dp[0][0]与现金数dp[0][1]。dp[0][0] =M/prices[0];//初始持有股票数
dp[0][1] = M;//最开始就为本金M=10000元
第四步:确定遍历顺序:
由题可知dp[i][1]的求出需要依赖dp[i-1][1]与dp[i-1][0]。所以从左向右遍历。
第五步:举例推导:prices[i]={1.0,2.0,1.0,2.0,2.0,3.0,2.0}注意推导从prices[1]开始
dp[1][0]=max(10000股,5000股)=10000股;
dp[1][1]=max(10000元,20000元)=20000元;
dp[2][0]=max(dp[1][0],dp[1][1]/prices[2])=20000股
dp[2][1]=max(dp[1][1],dp[1][0]*prices[2])=20000元
dp[3][0]=20000股
dp[3][1]=max(dp[2][1],dp[2][0]*prices[3])=40000元
dp[4][0]=20000股
dp[4][1]=40000元
dp[5][0]=max(20000,40000/3.0)=20000股
dp[5][1]=max(40000,20000*3.0)=60000元
dp[6][0]=max(20000,60000/2.0)=30000股
dp[6][1]=max(60000,30000*2.0)=60000元
即dp[6][1]为最大毛利润。
其中可以看到dp[5][1]与dp[6][1]所求的值一样,这是因为我们只知道7天的股市变化,而dp[6][1]就是把之前赚到的钱在最后一天里继续全部买下股票,然后再在当天继续卖出,等于是没有赚。赚的钱还是之前你所赚的。
代码如下:
#include<iostream>
#include<vector>
using namespace std;
double M=10000.0;
double maxProfit(vector<double>& prices) {
int len = prices.size();
vector<vector<double>> dp(len, vector<double>(2, 0));
dp[0][0] =M/prices[0];//持有股票数
dp[0][1] = M;//卖出股票所得现金
for (int i = 1; i < len; i++) {
dp[i][0] =max(dp[i-1][0],dp[i-1][1]/prices[i]); //锁定最值得的股票数
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0]*prices[i]);//即获得的毛利润
}
return dp[len - 1][1];//最大毛利润
}
int main() {
vector<double>p = {1.0,2.0,1.0,2.0,2.0,3.0,2.0};
cout<<maxProfit(p)-M;
}
结果:50000;dp[len-1][1]-M:即为纯利润。