往期股票问题
【温故知新】121. 买卖股票的最佳时机
动态规划、双指针实现
题目描述
给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [7,1,5,3,6,4] 输出: 7 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 示例 2:
输入: prices = [1,2,3,4,5] 输出: 4 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 示例 3:
输入: prices = [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
1 <= prices.length <= 3 * 104 0 <= prices[i] <= 104
解题思路
贪心算法
- 单独交易日:假设当天加个为p1,第二天价格为p2,则第二天卖出的利润为profit=p2-p1(profit<0,则亏损不卖)
- 连续上涨交易日:假设连续上涨交易价格为p1,p2,p3,...pn;则第一天买入,第n天卖出;最大利润profit=pn-p1;
- 这种情况等价于每天都买入卖出;pn-p1=(p2-p1)+(p3-p2)+...(pn-pn-1);
- 连续亏损交易日:不买卖;
时空复杂度
- 时间复杂度 O(N) : 只需遍历一次price;
- 空间复杂度 O(1) : 变量使用常数额外空间。
代码
function maxProfit(prices: number[]): number {
let profit:number=0;
for(let i=1;i<prices.length;i++){
let res=prices[i]-prices[i-1];
if(res>0){ // 如果有利润就卖出;可以当天卖出并在当天再买入的情况下;
profit+=res;
}//
}// end of for loop
return profit
};
动态规划
动态规划三部曲
- 定义dp含义
- 定义dp[n][2]:
- n代表第n天有2种状态,持有或者不持有
- dp[i][0] 第i天不持有获得的最大利润;
- dp[i][1] 第i天持有获得的最大利润;(tip:是持有不是买入)
- 定义状态转移方程:
- dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i])
对于今天不持有,可以从两个状态转移过来:1. 昨天也不持有;2. 昨天持有,今天卖出。两者取较大值。
- dp[i][1]=Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);
对于今天持有,可以从两个状态转移过来:1. 昨天也持有;2. 昨天不持有,今天买入。两者取较大值。
- 初始化dp;
- 不持有:dp[0][0]=0;
- 持有:dp[0][1]=-prices[0] ((即花了price[0] 的钱买入)) 由于dp[n][0]>dp[i][1],当天不持有股票利润一定大于当天持有股票,因此返回dp[len-1][0]即可
时空复杂度
- 时间复杂度:O(n),遍历一遍即可。
- 空间复杂度:O(n)
代码
function maxProfit(prices: number[]): number {
// 动态规划;
// 定义dp[n][2]:
// dp[i][0] 第i天不持有获得的最大利润;
// dp[i][1] 第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]);
// dp初始化
// dp[0][0]=0;
// dp[0][1]=-prices[0]
let len=prices.length;
let dp=new Array(len);
for(let i=0;i<len;i++){
dp[i]=new Array(2).fill(0)
}
dp[0][0]=0;
dp[0][1]=-prices[0]
for(let 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]);
}// end of for loop
return dp[len-1][0]
};
优化:状态转移的时候,dp[i] 只会从 dp[i-1] 转移得来,因此第一维可以去掉:
时空复杂度
- 时间复杂度:O(n),遍历一遍即可。
- 空间复杂度:O(1)
function maxProfit(prices: number[]): number {
// 动态规划;
let len=prices.length;
let dp=new Array(2).fill(0);
dp[0]=0;
dp[1]=-prices[0]
for(let i=1;i<len;i++){
let temp=dp[0]
dp[0]=Math.max(dp[0],dp[1]+prices[i])
dp[1]=Math.max(temp-prices[i],dp[1]);
}// end of for loop
return dp[0]
};
往期动态规划回顾
完全背包🎒问题
【温故知新】322. 零钱兑换
动画演示-完全背包问题最小解-动态规划实现
【温故知新】518. 零钱兑换 II
完全背包问题组合解-动态规划实现
【温故知新】377. 组合总和 Ⅳ
完全背包问题排列解-动态规划实现
【温故知新】70. 爬楼梯进阶版
完全背包🎒问题AC-动态规划实现
01背包🎒问题
【温故知新】474. 一和零
01背包🎒问题最大解-动态规划实现
【温故知新】494. 目标和
表达式转化为01背包🎒问题-动态规划实现