跳转至

122. 买卖股票的最佳时机 II

题目描述

给你一个整数数组 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。
最大总利润为 4 + 3 = 7 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。
最大总利润为 4 。

示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0。

 

提示:

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices[i] <= 104

解法

方法一:贪心

从第二天开始,如果当天股价大于前一天股价,则在前一天买入,当天卖出,即可获得利润。如果当天股价小于前一天股价,则不买入,不卖出。也即是说,所有上涨交易日都做买卖,所有下跌交易日都不做买卖,最终获得的利润是最大的。

时间复杂度 \(O(n)\),其中 \(n\) 为数组 prices 的长度。空间复杂度 \(O(1)\)

1
2
3
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        return sum(max(0, b - a) for a, b in pairwise(prices))
1
2
3
4
5
6
7
8
9
class Solution {
    public int maxProfit(int[] prices) {
        int ans = 0;
        for (int i = 1; i < prices.length; ++i) {
            ans += Math.max(0, prices[i] - prices[i - 1]);
        }
        return ans;
    }
}
1
2
3
4
5
6
7
8
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int ans = 0;
        for (int i = 1; i < prices.size(); ++i) ans += max(0, prices[i] - prices[i - 1]);
        return ans;
    }
};
1
2
3
4
5
6
7
8
9
func maxProfit(prices []int) (ans int) {
    for i, v := range prices[1:] {
        t := v - prices[i]
        if t > 0 {
            ans += t
        }
    }
    return
}
1
2
3
4
5
6
7
function maxProfit(prices: number[]): number {
    let ans = 0;
    for (let i = 1; i < prices.length; i++) {
        ans += Math.max(0, prices[i] - prices[i - 1]);
    }
    return ans;
}
1
2
3
4
5
6
7
8
9
impl Solution {
    pub fn max_profit(prices: Vec<i32>) -> i32 {
        let mut res = 0;
        for i in 1..prices.len() {
            res += (0).max(prices[i] - prices[i - 1]);
        }
        res
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
    let ans = 0;
    for (let i = 1; i < prices.length; i++) {
        ans += Math.max(0, prices[i] - prices[i - 1]);
    }
    return ans;
};
1
2
3
4
5
6
7
8
9
public class Solution {
    public int MaxProfit(int[] prices) {
        int ans = 0;
        for (int i = 1; i < prices.Length; ++i) {
            ans += Math.Max(0, prices[i] - prices[i - 1]);
        }
        return ans;
    }
}

方法二:动态规划

我们设 \(f[i][j]\) 表示第 \(i\) 天交易完后的最大利润,其中 \(j\) 表示当前是否持有股票,持有股票时 \(j=0\),不持有股票时 \(j=1\)。初始状态为 \(f[0][0]=-prices[0]\),其余状态均为 \(0\)

如果当前持有股票,那么可能是前一天就持有股票,今天什么都不做,即 \(f[i][0]=f[i-1][0]\);也可能是前一天不持有股票,今天买入股票,即 \(f[i][0]=f[i-1][1]-prices[i]\)

如果当前不持有股票,那么可能是前一天就不持有股票,今天什么都不做,即 \(f[i][1]=f[i-1][1]\);也可能是前一天持有股票,今天卖出股票,即 \(f[i][1]=f[i-1][0]+prices[i]\)

因此,我们可以写出状态转移方程:

\[ \begin{cases} f[i][0]=\max(f[i-1][0],f[i-1][1]-prices[i])\\ f[i][1]=\max(f[i-1][1],f[i-1][0]+prices[i]) \end{cases} \]

最终的答案即为 \(f[n-1][1]\),其中 \(n\) 为数组 prices 的长度。

时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)。其中 \(n\) 为数组 prices 的长度。

1
2
3
4
5
6
7
8
9
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        f = [[0] * 2 for _ in range(n)]
        f[0][0] = -prices[0]
        for i in range(1, n):
            f[i][0] = max(f[i - 1][0], f[i - 1][1] - prices[i])
            f[i][1] = max(f[i - 1][1], f[i - 1][0] + prices[i])
        return f[n - 1][1]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[][] f = new int[n][2];
        f[0][0] = -prices[0];
        for (int i = 1; i < n; ++i) {
            f[i][0] = Math.max(f[i - 1][0], f[i - 1][1] - prices[i]);
            f[i][1] = Math.max(f[i - 1][1], f[i - 1][0] + prices[i]);
        }
        return f[n - 1][1];
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int f[n][2];
        f[0][0] = -prices[0];
        f[0][1] = 0;
        for (int i = 1; i < n; ++i) {
            f[i][0] = max(f[i - 1][0], f[i - 1][1] - prices[i]);
            f[i][1] = max(f[i - 1][1], f[i - 1][0] + prices[i]);
        }
        return f[n - 1][1];
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func maxProfit(prices []int) int {
    n := len(prices)
    f := make([][2]int, n)
    f[0][0] = -prices[0]
    for i := 1; i < n; i++ {
        f[i][0] = max(f[i-1][0], f[i-1][1]-prices[i])
        f[i][1] = max(f[i-1][1], f[i-1][0]+prices[i])
    }
    return f[n-1][1]
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Solution {
    public int MaxProfit(int[] prices) {
        int f1 = -prices[0], f2 = 0;
        for (int i = 1; i < prices.Length; ++i)
        {
            f1 = Math.Max(f1, f2 - prices[i]);
            f2 = Math.Max(f2, f1 + prices[i]);
        }
        return f2;
    }
}

方法三:动态规划(空间优化)

我们可以发现,在方法二中,第 \(i\) 天的状态,只与第 \(i-1\) 天的状态有关,因此我们可以只用两个变量来维护第 \(i-1\) 天的状态,从而将空间复杂度优化到 \(O(1)\)

时间复杂度 \(O(n)\),其中 \(n\) 为数组 prices 的长度。空间复杂度 \(O(1)\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        f = [-prices[0], 0]
        for i in range(1, n):
            g = [0] * 2
            g[0] = max(f[0], f[1] - prices[i])
            g[1] = max(f[1], f[0] + prices[i])
            f = g
        return f[1]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[] f = new int[] {-prices[0], 0};
        for (int i = 1; i < n; ++i) {
            int[] g = new int[2];
            g[0] = Math.max(f[0], f[1] - prices[i]);
            g[1] = Math.max(f[1], f[0] + prices[i]);
            f = g;
        }
        return f[1];
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int f[2] = {-prices[0], 0};
        for (int i = 1; i < n; ++i) {
            int g[2];
            g[0] = max(f[0], f[1] - prices[i]);
            g[1] = max(f[1], f[0] + prices[i]);
            f[0] = g[0], f[1] = g[1];
        }
        return f[1];
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func maxProfit(prices []int) int {
    n := len(prices)
    f := [2]int{-prices[0], 0}
    for i := 1; i < n; i++ {
        g := [2]int{}
        g[0] = max(f[0], f[1]-prices[i])
        g[1] = max(f[1], f[0]+prices[i])
        f = g
    }
    return f[1]
}

评论

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy