121. 买卖股票的最佳时机
思路:动态规划
1. dp数组及其下标的含义:dp[i][0] 代表第i天「持有」股票所得最多现金,dp[i][1]代表第i天不持有股票所得最多现金;
2. 递推公式:dp[i][0] = max(dp[i-1][0], -prices[i]), dp[i][1] = max(dp[i-1][0]+prices[i], dp[i-1][1]);
3. 初始化:dp[0][0] = -prices[0], dp[0][1] = 0;
4. 遍历顺序:从前往后;
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][] dp = new int[len][2];
dp[0][0] = -prices[0];
dp[0][1] = 0;
for(int i=1;i<len;i++){
dp[i][0] = Math.max(dp[i-1][0], -prices[i]);//注意:只买卖一次
dp[i][1] = Math.max(dp[i-1][0]+prices[i], dp[i-1][1]);
}
return dp[len-1][1];
}
}
思路:贪心算法
1. 左边取最小值,右边取最大值,差值即为最大利润;
class Solution {
public int maxProfit(int[] prices) {
int min = Integer.MAX_VALUE;
int res = 0;
for(int i=0;i<prices.length;i++){
min = Math.min(min,prices[i]);
res = Math.max(res,prices[i]-min);
}
return res;
}
}
122.买卖股票的最佳时机II
思路:动态规划
1. 基本同上;
2. 区别:由于可以买卖多次,dp[i][0] 递推公式为Math.max(dp[i-1][0], dp[i-1][1]-prices[i]);
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][] dp = new int[len][2];
dp[0][0] = -prices[0];
dp[0][1] = 0;
for(int i=1;i<len;i++){
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1]-prices[i]);
dp[i][1] = Math.max(dp[i-1][0]+prices[i], dp[i-1][1]);
}
return dp[len-1][1];
}
}
优化空间:
1. 只维护2个状态:dp[0]表示持有,dp[1]表示卖出;
2. 递推公式:dp[0] = Math.max(dp[0],dp[1]-prices[i-1]); dp[1] = Math.max(dp[0] + prices[i-1]);
// 优化空间
class Solution {
public int maxProfit(int[] prices) {
int[] dp = new int[2];
// 0表示持有,1表示卖出
dp[0] = -prices[0];
dp[1] = 0;
for(int i = 1; i <= prices.length; i++){
// 前一天持有; 既然不限制交易次数,那么再次买股票时,要加上之前的收益
dp[0] = Math.max(dp[0], dp[1] - prices[i-1]);
// 前一天卖出; 或当天卖出,当天卖出,得先持有
dp[1] = Math.max(dp[1], dp[0] + prices[i-1]);
}
return dp[1];
}
}