算法练习day42

93 阅读3分钟

一、买卖股票的最佳时机

暴力解法

时间复杂度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
};

动态规划

五部曲

  1. 确定dp数组含义, dp[i][0],第i天,持有股票所得的最多现金,dp[i][1],第i天,不持有股票所得的最多现金
  2. 确定递推公式
    1. dp[i][0],两种情况,第i-1天就持有股票dp[i-1][0],第i天买入股票, -price[i],dp[i][0] = Math.max(dp[i-1][0], -price[i])
    2. 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])
  3. dp[0][0] = -price[0]; dp[0][1] = 0
  4. 确定遍历顺序,从前到后
  5. 举例推导

时间复杂度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

和上一题的区别在于,可以多次买票股票

递推公式

  1. 第i天持有股票的最大金额
    1. 第i-1天持有股票,dp[i-1][0]
    2. 第i天买入股票,dp[i-1][1] - price[i],这里和上一题不同,因为可以交易多次,第i次买入,之前多次交易可能会有利润
    3. dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i])
  2. 第i天不持有股票的最大金额
    1. 第i-1天不持有,dp[i-1][1]
    2. 第i天卖出股票,dp[i-1][0] + price[i]
    3. dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i])

时间复杂度: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]
};