在面试和金融相关的公司的时候,非常有可能遇到这类题目。这类题也算是动规的常见题目了。
股票无限次交易
可以进行无限次的交易
思路一:投机取巧法
因为已经事先知道了每一天的股票价格,所以后一天比前一天价格高,就前一天买入,后一天卖出。
如果价格后一天比前一天价格低或者是一样的,我就不买入也不卖出
public int maxProfit (int[] prices) {
// write code here
int profit = 0;
for(int i= 1;i < prices.length;i++){
if(prices[i] > prices[i-1]){
profit += prices[i]-prices[i-1];
}
}
return profit;
}
思路二:动态规划
设置动态规划的方程是
dp[i] [2] i表示的是第i天,2表示的是两种状态 0 表示第i天不持有股票,1表示第i天持有股票 可以获得的最大收益
public int maxProfit2 (int[] prices) {
// write code here
if(prices.length == 0) return 0;
int[][] dp = new int[prices.length][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i< prices.length;i++){
//第i天未持有股票,两个可能:
//1.在前面i-1天都持有,第i天卖掉了,卖掉价值增加。dp[1][i - 1] + prices[i - 1]
//2.到当前为止都为未持有,维持第i-1天的结果。dp[0][i - 1]
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
//第i天持有股票,两个可能:
//1.在前面i-1天都未持有,第i天买入了,总价值减少。dp[0][i - 1] - prices[i - 1]
//2.到当前为止都为持有,维持第i-1天的结果。dp[1][i - 1]
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);
}
//返回最后一天不持有股票的可以获得的最大价值
return dp[prices.length-1][0];
}
股票的最大交易(二)
和第一个不同的就是对于交易的次数有了限制。
思路:动态规划
还是使用动态规划,两个维度,第一个维度表示天数,第二个维度表示交易,但是第二个维度有5中状态。
dp[i] [0] 表示从开始第i天不持有股票
dp[i] [1] 表示第i天持有股票,且是第一次持有。
dp[i] [2] 表示第i天不持有股票,且是第一次不持有。
dp[i] [3] 表示第i天持有股票,且是第二次持有。
dp[i] [4] 表示第i天不持有股票,且是第二次不持有。
public int maxProfitII (int[] prices) {
if(prices.length == 0) return 0;
int[][] dp=new int[prices.length][5];
dp[0][1]=-prices[0];
dp[0][3]=-prices[0];
for (int i=1;i<prices.length;i++){
dp[i][0]=dp[i-1][0];
//之前就持有 和 第i天买入
dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);
//之前就卖出了 和 当天卖出
dp[i][2]=Math.max(dp[i-1][2],dp[i-1][1]+prices[i]);
//之前就已经进行第二次交易了 和 第i天进行第二次交易买入
dp[i][3]=Math.max(dp[i-1][3],dp[i-1][2]-prices[i]);
//之前就已经进行第二次交易了 和 第i天进行第二次交易卖出
dp[i][4]=Math.max(dp[i-1][4],dp[i-1][3]+prices[i]);
}
//关于这里为什么可以直接返回的是交易两次不持有股票的状态
//而不是在一次都没有交易、交易一次和交易两次后不持有股票中选择最大的收益
//暂时还不太明白
return dp[prices.length-1][4];
}
买卖股票的最好时机
这道题也是很经典的一道题,在leetcode 121 中也有原题。
思路:动态规划
dp[i] [0] 表示第i天不持有股票
dp[i] [1] 表示第i天持有股票
public int maxProfit (int[] prices) {
// write code here
if(prices.length == 0) return 0;
int[][] dp=new int[prices.length][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for(int i =1;i<prices.length;i++){
//当天不持有股票 可能是前一天不持有 或者是当天卖掉了
dp[i][0] = Math.max(dp[i-1][0] , dp[i-1][1]+prices[i]);
//当天持有股票可能是 前一天持有 或者是当天是第一次买入
//一定只有0-prices[i] 才能体现出是只可以交易一次
//如果写dp[i-1][0] 就无法确定交易了几次
//因为上一个 dp[i-1][0] 不持有股票的状态可能是已经交易过的
dp[i][1] = Math.max(dp[i-1][1],0-prices[i]);
}
return dp[prices.length-1][0];
}