目录
总的状态转移方程:
121. 买卖股票的最佳时机(交易一次)
- 只能有一次买入,一次买出。求出最大的利润是多少。
- 我起初的思路是,用动态规划的方式。F(i)表示含第i天能获取的最大收益。
F(i) = max { F(i-1) , 第i天的股票价格 - 第i天以前的最低股票价格 }
class Solution {
public int maxProfit(int[] prices) {
//动态规划解题,设每个序号的股价为p(i)
//设第包括序号i之前的最大收益为F(i),min表示i序号之前的最小值
//F(i) = max{F(i-1), p(i)-min}
if(prices.length < 2){
return 0;
}
int min = Math.min(prices[0], prices[1]);
int f = prices[1] - prices[0];
for(int i = 2; i<prices.length; i++){
min = prices[i] < min ? prices[i] : min;
f = Math.max(f, prices[i] - min);
}
return f > 0 ? f : 0;
}
}
- 套用总的状态转移方程:
public class Solution {
public int maxProfit(int[] prices) {
int dp0 = 0;
int dp1 = Integer.MIN_VALUE;
for (int i = 0; i < prices.length; i++) {
// 手中没有股票 可能昨天就没有;昨天有,今天抛售了。
dp0 = Math.max(dp0, dp1 + prices[i]);
// 手中有股票 可能昨天没有,今天刚买的(因为只让买一次,所以新买的话,dp为负的股票价格);昨天就有
dp1 = Math.max(dp1, - prices[i]);
}
return Math.max(dp0, dp1);
}
}
122. 买卖股票的最佳时机 II(交易无穷次)
直接套用普适性的状态转移方程:发现和第一道题目只有一点点不同。
public class Demo02 {
public int maxProfit(int[] prices) {
int dp0 = 0;
int dp1 = Integer.MIN_VALUE;
for (int i = 0; i < prices.length; i++) {
int tmp = dp0;
// 手中没有股票 可能昨天就没有;昨天有,今天抛售了。
dp0 = Math.max(dp0, dp1 + prices[i]);
// 手中有股票 可能昨天没有,今天刚买的(因为只让买一次,所以新买的话,dp为负的股票价格);昨天就有
dp1 = Math.max(dp1, tmp - prices[i]);
}
return Math.max(dp0, dp1);
}
}
123. 买卖股票的最佳时机 III(交易两次)
public class Solution {
public int maxProfit(int[] prices) {
int dp_2_0 = 0;// 第二次交易,手中没有股票
int dp_2_1 = Integer.MIN_VALUE;// 第二次交易,手中有股票
int dp_1_0 = 0;// 第一次交易,手中没有股票
int dp_1_1 = Integer.MIN_VALUE;// 第一次交易,手中有股票
for (int price : prices) {
// 没有股票,可能昨天就没有,或者今天卖了
dp_2_0 = Math.max(dp_2_0, dp_2_1 + price);
dp_1_0 = Math.max(dp_1_0, dp_1_1 + price);
// 持有股票。可能昨天就持有。或者今天新买的
dp_2_1 = Math.max(dp_2_1, dp_1_0 - price);
dp_1_1 = Math.max(dp_1_1, -price);
}
return dp_2_0;
}
}
188. 买卖股票的最佳时机 IV(k次交易)
需要对k进行一下判断,否则会超出内存限制。
public class Solution {
public int maxProfit(int k, int[] prices) {
// 这种情况下,相当于交易次数为无穷次的情况。
if (k > prices.length / 2) {
int dp0 = 0;
int dp1 = Integer.MIN_VALUE;
for (int i = 0; i < prices.length; i++) {
int tmp = dp0;
// 手中没有股票 可能昨天就没有;昨天有,今天抛售了。
dp0 = Math.max(dp0, dp1 + prices[i]);
// 手中有股票 可能昨天没有,今天刚买的(因为只让买一次,所以新买的话,dp为负的股票价格);昨天就有
dp1 = Math.max(dp1, tmp - prices[i]);
}
return Math.max(dp0, dp1);
}
// k<= len/2
int[] dp_k_1 = new int[k + 1]; // k次交易,手中有股票
int[] dp_k_0 = new int[k + 1]; // k次交易,手中没有股票
Arrays.fill(dp_k_1, Integer.MIN_VALUE);
for (int price : prices) {
for (int i = 1; i <= k; i++) {
// 第i次交易,手上没有股票,
dp_k_0[i] = Math.max(dp_k_0[i], dp_k_1[i] + price);
dp_k_1[i] = Math.max(dp_k_1[i], dp_k_0[i - 1] - price);
}
}
Arrays.sort(dp_k_0);
return dp_k_0[k];
}
}
309. 最佳买卖股票时机含冷冻期
- 可以发现,和没有冷冻期相比。就是当买入股票的时候,需要是在前两天没买股票的基础上进行。
public class Solution {
public int maxProfit(int[] prices) {
// 含有冷冻期,可以交易无数次。
// 1. 手中可以有股票,可以没股票
// 2. 天数变量
int dp_0 = 0;
int dp_1 = Integer.MIN_VALUE;
int tmp = 0;// 代表dp_0 i-2那天的。
for (int i = 0; i < prices.length; i++) {
int x = dp_0;// 昨天的。
dp_0 = Math.max(dp_0, dp_1 + prices[i]);
dp_1 = Math.max(dp_1, tmp - prices[i]);
tmp = x;// 明天来看的话,tmp就是i-2天的。
}
return dp_0;
}
}
714. 买卖股票的最佳时机含手续费
public class Solution {
public int maxProfit(int[] prices, int fee) {
// 有手续费用。我们假定买入的时候需要支付手续费。
int dp_0 = 0;
int dp_1 = Integer.MIN_VALUE;
for (int price : prices) {
dp_0 = Math.max(dp_0, dp_1 + price);
dp_1 = Math.max(dp_1, dp_0 - price - fee);
}
return dp_0;
}
}