121. 買賣股票的最佳時機
題目連結:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
文章講解:https://programmercarl.com/0121.買賣股票的最佳時機.html
題目難度:簡單
影片講解:https://www.bilibili.com/video/BV1Xe4y1u77q
題目狀態:有一半的思路
思路一:貪心
對陣列進行遍歷,分別儲存兩個變數:最小的買入時間left
,最大的獲利金額ans
,遍歷完就得到答案了。
程式碼:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int left = INT_MAX;
int ans = 0;
for(int i = 0; i < prices.size(); ++i) {
left = min(left, prices[i]);
ans = max(ans, prices[i] - left);
}
return ans;
}
};
思路二:動規
建立一個二維動規陣列dp[i][]
,其大小為vector<len, vector<int>(2)>
。
dp[i][0]
表示在第i天持有所花費的錢,此時並不一定是在i天買入的,也可能是在i-1天買入的,這個就是其動規的公式:dp[i][0] = max(dp[i - 1][0], -price[i])
。dp[i][1]
表示在第i天整到的最多的錢,此時也並不一定必須在i天賣出,也可能是在i-1天賣出的,取決於誰獲利最多,動規公式如下:dp[i][1] = max(price[i] + dp[i - 1][0], dp[i - 1][0])
。
程式碼:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if(len == 0) return 0;
vector<vector<int>> dp(len, vector<int>(2));
dp[0][0] = -prices[0];
dp[0][1] = 0;
for(int i = 1; i < len; ++i) {
dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1] = max(prices[i] + dp[i - 1][0], dp[i - 1][1]);
}
return dp[len - 1][1];
}
};
思路二程式碼改進:
由於dp[i][]
只有dp[i - 1][]
來進行動規,因此只需要維持這兩個數就行,不需要維護其他數,採用滑動視窗的形式,程式碼如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
vector<vector<int>> dp(2, vector<int>(2)); // 注意這裡只開闢了一個2 * 2大小的二維陣列
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);
dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
}
return dp[(len - 1) % 2][1];
}
};
122. 買賣股票的最佳時機 II
題目連結:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
文章講解:https://programmercarl.com/0122.買賣股票的最佳時機II(動態規劃).html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV1D24y1Q7Ls
題目狀態:有一半的思路
思路一:貪心
這題在學習貪心演算法的時候做過,只需要遍歷陣列,然後將具有正收益的盈利金額加起來。
程式碼:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
for(int i = 1; i < prices.size(); ++i) {
res += max(prices[i] - prices[i - 1], 0);
}
return res;
}
};
思路二:動態規劃
這裡和上一題一樣,也要維持一個二維動規陣列,但有一個地方需要改變,就是在dp[i][0]
的計算上,上一題因為只能進行一次交易,所以dp[i][0]
要麼是dp[i - 1][0]
(在第i天之前已經進行買入),要麼是-price[i]
(在當天買入)。但這道題中,我們可以進行多次交易,因此dp[i][0]
要麼是dp[i - 1][0]
(在第i天之前進行買入),要麼是dp[i - 1][1] - price[i]
(在當天進行買入,我們要將之前的收益也要加進來)。
要始終記得:dp[i][0]
表示第i天持有股票的最大利潤;dp[i][1]
表示第i天不持有股票的最大利潤。
程式碼:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if(len == 0) return 0;
vector<vector<int>> dp(len, vector<int>(2));
dp[0][0] = -prices[0];
dp[0][1] = 0;
for(int i = 1; i < len; ++i) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1] = max(dp[i - 1][0] + prices[i], dp[i - 1][1]);
}
return dp[len - 1][1];
}
};
滾動陣列版本:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
vector<vector<int>> dp(2, vector<int>(2)); // 注意這裡只開闢了一個2 * 2大小的二維陣列
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);
dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
}
return dp[(len - 1) % 2][1];
}
};
123. 買賣股票的最佳時機 III
題目連結:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
文章講解:https://programmercarl.com/0123.買賣股票的最佳時機III.html
題目難度:困難
影片講解:https://www.bilibili.com/video/BV1WG411K7AR
題目狀態:沒思路
思路:
這次的動規陣列主要維護的是五個狀態:
- 無操作
- 第一次持有股票
- 第一次不持有股票
- 第二次持有股票
- 第二次不持有股票
dp[i][j]
中i表示第i天,j就是上面五個狀態,dp[i][j]
表示第i天狀態j的所剩最大現金。
因此:每個狀態就會有兩種操作:
- 有操作:假設是狀態1,那麼就表示當天買入股票了,則
dp[i][1] = dp[i - 1][0] - prices[i]
。 - 沒操作:就是這天沒進行買入操作,那麼
dp[i][1] = dp[i - 1][1]
。
其他狀態同上。
程式碼:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if(len == 0) return 0;
vector<vector<int>> dp(len, vector<int>(5));
dp[0][1] = -prices[0];
dp[0][3] = -prices[0];
for(int i = 1; i < len; ++i) {
dp[i][0] = dp[i - 1][0];
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
return dp[len - 1][4];
}
};