买卖股票1
买卖股票2
回溯
namespace l122_1 { function maxProfit(prices: number[]): number { // dfs的参数往往是动态规划的状态 const memo: number[][] = new Array(prices.length) .fill(0) .map((item) => new Array(2).fill(-1)); // function dfs(state: boolean, i: number): number { /* * profit 表示当前状态下, [i...end]*还能*获利多少 * state 表示当前持有还是未买入。 只要买入state就是持有状态 * j:何时买入 */ // base case if (i === prices.length) { return 0; } // make choices if (state) { // 持有状态 卖出或继续持有 if (memo[i][1] !== -1) { return memo[i][1]; } let result = Math.max( prices[i] + dfs(false, i + 1), dfs(true, i + 1) ); memo[i][1] = result; return result; } else { // 非持有状态 买入或者继续非持有 if (memo[i][0] !== -1) { return memo[i][0]; } let result = Math.max( -prices[i] + dfs(true, i + 1), dfs(false, i + 1) ); memo[i][0] = result; return result; } } let result = dfs(false, 0); console.table(memo); return result; } maxProfit([7, 1, 5, 3, 6, 4]);}
动态规划
namespace l122_2 { function maxProfit(prices: number[]): number { /* * dfs的参数往往是动态规划的状态, 但是含义可能不一样, 回溯一般是自顶向下, 反之亦反。 * 状态/局面:dp[i][state] 表示state下,前i天最大 * base case dp[0][买入] = -nums[0] dp[0][卖出] = X * * */ const dp: number[][] = new Array(prices.length) .fill(0) .map((item) => new Array(2).fill(Number.NEGATIVE_INFINITY)); dp[0][0] = 0; dp[0][1] = -prices[0]; for (let i = 1; i < prices.length; i++) { // 持有状态 /* 当前是持有状态, 如果是i买入, 那么前面必须是非持有状态;如果不是i买入, 说明前面是持有状态 */ dp[i][1] = Math.max(dp[i - 1][1], -prices[i] + dp[i - 1][0]); // 非持有状态 dp[i][0] = Math.max(dp[i - 1][0], prices[i] + dp[i - 1][1]); } console.table(dp); // 最高利润肯定非持有状态取得 return dp[prices.length - 1][0] > 0 ? dp[prices.length - 1][0] : 0; } maxProfit([1, 2, 3, 4, 5]);}
总结
- 画出状态转移图
- 由
dfs获得灵感, dfs参数和dp状态往往是一样的, 不过其含义可能不同