LeetCode 121. 买卖股票的最佳时机
题目链接:121. 买卖股票的最佳时机
思路:之前用贪心算法做过这道题,今天使用动态规划的思想再做一遍。
- 确定dp数组及其下标的含义
我们遇到一支股票,有两种状态和两种选择:两种状态分别是已持有股票或者未持有股票;两种选择分别是买入该股票或者不买该股票,而当我们持有股票的时候,我们在每一天还有一种选择就是卖出手上的股票。所以每一天的状态转移应该有两种:持有股票时的最大金额和不持有股票时的最大金额。
dp[i][0] 表示第 i 天持有股票所得最多现金,dp[i][1] 表示第 i 天不持有股票所得最多现金。 - 确定递推公式
如果第 i 天持有股票即dp[i][0], 那么有两种状态可以选择:第 i-1 天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金,即dp[i - 1][0];或者在第 i 天买入股票,所得现金就是买入今天的股票后所得现金,即 -prices[i]。
如果第i天不持有股票即dp[i][1], 也有两种状态:第 i-1天 就没有持有股票,则保持现状,所得现金就是昨天不持有股票的所得现金,即dp[i - 1][1];第 i 天卖出股票,所得现金就是今天股票佳价格加上dp[i - 1][0]所拥有的现金(其实是负的,因为之前卖股票花出去的钱),即:prices[i] + dp[i - 1][0]。 - dp数组初始化
dp[0][0]对应的含义是第一天持有股票时的最大金额,既然持有股票那一定就要买入第一天的股票,所以dp[0][0]初始化为-prices[0]。
dp[0][1]对应的含义是第一天不持有股票时的最大金额,所以初始化为0即可。 - 确定遍历顺序
从前向后遍历 - 打印dp[len(nums)-1][1],因为不持有股票时所能拥有的最大金额一定是大于持有股票时的最大金额,所以dp[len(nums)-1][1]一定比dp[len(nums)-1][0]大。
Python版本:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
dp = [[0] * 2 for _ in range(n)]
dp[0][0] = -prices[0]
dp[0][1] = 0
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], -prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i])
return dp[-1][1]
时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)
go版本:
func maxProfit(prices []int) int {
n := len(prices)
dp := make([][]int, n)
for i:=0; i<n; i++ {
dp[i] = make([]int, 2)
}
dp[0][0] -= prices[0]
dp[0][1] = 0
for i := 1; i < n; i++ {
dp[i][0] = max(dp[i - 1][0], -prices[i])
dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
}
return dp[n-1][1]
}
func max(i, j int) int {
if i > j {
return i
} else {
return j
}
}
LeetCode 122. 买卖股票的最佳时机 II
题目链接:122. 买卖股票的最佳时机 II
思路:本题与上一题最大的区别在于可以多次买卖股票,而上一题至多有一次买入卖出,而在代码上体现的区别仅仅在于递推公式。
- 确定递推公式
上一题如果第 i 天持有股票即dp[i][0], 那么有两种状态可以选择:第 i-1 天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金,即dp[i - 1][0];或者在第 i 天买入股票,所得现金就是买入今天的股票后所得现金,即 -prices[i]。而本题是可以不止一次的买卖股票,所以在当前不持有股票的状态下,还有一种可能是之前已经进行过一次或多次完整的股票交易,所以dp[i][0]在第 i 天买入股票时,不应该是 -prices[i]了,而应该是之前能得到的最大值加上买股票所花费的钱,即dp[i - 1][1]-prices[i]。第i天不持有股票即dp[i][1]的两种状态不变。
Python版本:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
dp = [[0] * 2 for _ in range(n)]
dp[0][0] = -prices[0]
dp[0][1] = 0
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i])
return dp[-1][1]
时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)
go版本:
func maxProfit(prices []int) int {
n := len(prices)
dp := make([][]int, n)
for i:=0; i<n; i++ {
dp[i] = make([]int, 2)
}
dp[0][0] -= prices[0]
dp[0][1] = 0
for i := 1; i < n; i++ {
dp[i][0] = max(dp[i - 1][0], dp[i-1][1]-prices[i])
dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
}
return dp[n-1][1]
}
func max(i, j int) int {
if i > j {
return i
} else {
return j
}
}