- 題目連結:122. 買賣股票的最佳時機 II-中等
- 題目連結:55. 跳躍遊戲-中等
- 題目連結:45. 跳躍遊戲 II-中等
題目連結: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 * 10^4
0 <= prices[i] <= 10^4
如果每天都有利潤,那麼某一天買進,到某一天賣出,其實等於在這個區間每天買進賣出
其實我們需要收集每天的正利潤就可以,收集正利潤的區間,就是股票買賣的區間,而我們只需要關注最終利潤,不需要記錄區間。
那麼只收集正利潤就是貪心所貪的地方!
區域性最優:收集每天的正利潤,全域性最優:求得最大利潤。
程式碼如下:
// 時間複雜度: O(n)
// 空間複雜度: O(1)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
for (int i = 1; i < prices.size(); ++i) {
if (prices[i] - prices[i - 1] > 0)
res += (prices[i] - prices[i - 1]);
}
return res;
}
};
題目連結:55. 跳躍遊戲-中等
題目描述:
給你一個非負整數陣列 nums
,你最初位於陣列的 第一個下標 。陣列中的每個元素代表你在該位置可以跳躍的最大長度。
判斷你是否能夠到達最後一個下標,如果可以,返回 true
;否則,返回 false
。
示例 1:
輸入:nums = [2,3,1,1,4]
輸出:true
解釋:可以先跳 1 步,從下標 0 到達下標 1, 然後再從下標 1 跳 3 步到達最後一個下標。
示例 2:
輸入:nums = [3,2,1,0,4]
輸出:false
解釋:無論怎樣,總會到達下標為 3 的位置。但該下標的最大跳躍長度是 0 , 所以永遠不可能到達最後一個下標。
提示:
1 <= nums.length <= 10^4
0 <= nums[i] <= 10^5
遍歷思路:
可以從後往前遍歷,如果當前位置能夠到達所記錄的最後一個位置,那對其進行迭代,只要確保每個位置都能到達,即最後落在第一個下標,那說明可以跳到終點,如果不能落在第一個下標,那說明中間有地方斷了,即不能到達。
程式碼如下:
// 時間複雜度: O(n)
// 空間複雜度: O(1)
class Solution {
public:
bool canJump(vector<int>& nums) {
int index = nums.size() - 1;
for (int i = nums.size() - 2; i >= 0; --i) {
if (nums[i] >= index - i)
index = i;
}
if (index == 0)
return true;
return false;
}
};
貪心思路:
這個問題轉化為跳躍覆蓋範圍究竟可不可以覆蓋到終點!
每次移動取最大跳躍步數(得到最大的覆蓋範圍),每移動一個單位,就更新最大覆蓋範圍。
貪心演算法區域性最優解:每次取最大跳躍步數(取最大覆蓋範圍),整體最優解:最後得到整體最大覆蓋範圍,看是否能到終點。
程式碼如下:
// 時間複雜度: O(n)
// 空間複雜度: O(1)
class Solution {
public:
bool canJump(vector<int>& nums) {
if (nums.size() == 1)
return true;
int cover = 0;
for (int i = 0; i <= cover; ++i) {
cover = max(cover, i + nums[i]);
if (cover >= nums.size() - 1)
return true;
}
return false;
}
};
題目連結:45. 跳躍遊戲 II-中等
題目描述:
給定一個長度為 n
的 0 索引整數陣列 nums
。初始位置為 nums[0]
。
每個元素 nums[i]
表示從索引 i
向前跳轉的最大長度。換句話說,如果你在 nums[i]
處,你可以跳轉到任意 nums[i + j]
處:
0 <= j <= nums[i]
i + j < n
返回到達 nums[n - 1]
的最小跳躍次數。生成的測試用例可以到達 nums[n - 1]
。
示例 1:
輸入: nums = [2,3,1,1,4]
輸出: 2
解釋: 跳到最後一個位置的最小跳躍數是 2。
從下標為 0 跳到下標為 1 的位置,跳 1 步,然後跳 3 步到達陣列的最後一個位置。
示例 2:
輸入: nums = [2,3,0,1,4]
輸出: 2
提示:
1 <= nums.length <= 10^4
0 <= nums[i] <= 1000
- 題目保證可以到達
nums[n-1]
如果移動下標達到了當前這一步的最大覆蓋最遠距離了,還沒有到終點的話,那麼就必須再走一步來增加覆蓋範圍,直到覆蓋範圍覆蓋了終點
程式碼如下:
// 時間複雜度: O(n)
// 空間複雜度: O(1)
class Solution {
public:
int jump(vector<int>& nums) {
if (nums.size() == 1)
return 0;
int res = 0;
int cover = 0; // 當前覆蓋最遠距離下標
int next = 0; // 下一步覆蓋最遠距離下標
for (int i = 0; i < nums.size() - 1; ++i) {
next = max(next, i + nums[i]); // 更新下一步覆蓋最遠距離下標
if (cover == i) { // 遇到當前覆蓋最遠距離下標
++res; // 需要走下一步
cover = next; // 更新當前覆蓋最遠距離下標
// 下面這一步判斷可免,不過會繼續遍歷到終點
if (cover >= nums.size() - 1) // 當前覆蓋最遠距到達集合終點,不用做ans++操作了,直接結束
break;
}
}
return res;
}
};