一、买卖股票的最佳时机
暴力解法
时间复杂度On^2,空间复杂度O1
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
// 暴力解法
let res = 0
for(let i = 0; i < prices.length - 1; i++) {
for(let j = i+1; j < prices.length; j++) {
res = Math.max(res, prices[j] - prices[i])
}
}
return res
};
贪心解法
时间复杂度On,空间复杂度O1
取最左最小值,取最后最大值,得到的差值就是最大利润
var maxProfit = function(prices) {
let res = 0
let low = Infinity
for(let i = 0; i < prices.length; i++) {
low = Math.min(low, prices[i])
res = Math.max(res, prices[i] - low)
}
return res
};
动态规划
五部曲
- 确定dp数组含义,
dp[i][0],第i天,持有股票所得的最多现金,dp[i][1],第i天,不持有股票所得的最多现金 - 确定递推公式
dp[i][0],两种情况,第i-1天就持有股票dp[i-1][0],第i天买入股票,-price[i],dp[i][0] = Math.max(dp[i-1][0], -price[i])dp[i][1], 两种情况,第i-1天就不持有股票dp[i-1][1],第i天卖出股票,price[i],dp[i][1] = Math.max(dp[i-1][1], price[i] + dp[i-1][0])
dp[0][0] = -price[0]; dp[0][1] = 0- 确定遍历顺序,从前到后
- 举例推导
时间复杂度On,空间复杂度On
var maxProfit = function(prices) {
let dp = new Array(prices.length).fill(0).map(_ => [-Infinity, -Infinity])
dp[0][0] = -prices[0]
dp[0][1] = 0
for(let i = 1; i < prices.length;i++) {
dp[i][0] = Math.max(dp[i-1][0], -prices[i])
dp[i][1] = Math.max(dp[i-1][1], prices[i] + dp[i-1][0])
}
return dp[prices.length - 1][1]
};
动态规划-滚动数组
dp[i]只依赖于于dp[i-1]的状态,只需要记录当前的状态和前一天的状态就可以了,可以使用滚动数组来节省空间
时间复杂度On,空间复杂度O1
var maxProfit = function(prices) {
let dp = new Array(2).fill(0).map(_ => [-Infinity, -Infinity])
dp[0][0] = -prices[0]
dp[0][1] = 0
for(let i = 1; i < prices.length;i++) {
dp[i % 2][0] = Math.max(dp[(i-1)%2][0], -prices[i])
dp[i % 2][1] = Math.max(dp[(i-1)%2][1], prices[i] + dp[(i-1)%2][0])
}
return dp[(prices.length - 1)%2][1]
};
二、买卖股票的最佳时机2
和上一题的区别在于,可以多次买票股票
递推公式
- 第i天持有股票的最大金额
- 第i-1天持有股票,
dp[i-1][0] - 第i天买入股票,
dp[i-1][1] - price[i],这里和上一题不同,因为可以交易多次,第i次买入,之前多次交易可能会有利润 dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i])
- 第i-1天持有股票,
- 第i天不持有股票的最大金额
- 第i-1天不持有,
dp[i-1][1] - 第i天卖出股票,
dp[i-1][0] + price[i] dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i])
- 第i-1天不持有,
时间复杂度:O(n),空间复杂度:O(n)
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let dp = new Array(prices.length).fill(0).map(_ => [Infinity, Infinity])
dp[0][0] = -prices[0]
dp[0][1] = 0
for(let i = 1; i < prices.length;i++) {
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i])
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i])
}
return dp[prices.length - 1][1]
};
滚动数组版本
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let dp = new Array(2).fill(0).map(_ => [-Infinity, -Infinity])
dp[0][0] = -prices[0]
dp[0][1] = 0
for(let i = 1; i < prices.length;i++) {
dp[i % 2][0] = Math.max(dp[(i-1)%2][0], dp[(i-1)%2][1] - prices[i])
dp[i % 2][1] = Math.max(dp[(i-1)%2][1], dp[(i-1)%2][0] + prices[i])
}
return dp[(prices.length - 1) % 2][1]
};