領釦-121/122 最佳買賣時機 Best Time to Buy and Sell MD
目錄
Markdown版本筆記 | 我的GitHub首頁 | 我的部落格 | 我的微信 | 我的郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | [email protected] |
領釦-121/122 最佳買賣時機 Best Time to Buy and Sell MD
***
目錄
===
買賣股票的最佳時機 -121
陣列 貪心演算法
題目
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
如果你最多隻允許完成一筆交易(即買入和賣出一支股票),設計一個演算法來計算你所能獲取的最大利潤。
注意你不能在買入股票前賣出股票。
示例 1:
輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天的時候買入,在第 5 天的時候賣出,最大利潤 = 6-1 = 5 。
注意利潤不能是 7-1 = 6, 因為賣出價格需要大於買入價格。
示例 2:
輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種情況下, 沒有交易完成, 所以最大利潤為 0。
方法宣告:
class Solution {
public int maxProfit(int[] prices) {
}
}
暴力法
class Solution { public int maxProfit(int[] prices) { int max = 0; for (int i = 0; i < prices.length; i++) { for (int j = i + 1; j < prices.length; j++) { max = Math.max(max, prices[j] - prices[i]); } } return max; } }
時間複雜度:O(n^2)
空間複雜度:O(1)
貪心演算法(波峰波谷法)
對於這道題,我們很明顯能感覺到,不是單純的找出陣列中的最小值和最大值,然後求他們的差的,因為最小值不一定在最大值的前面。
但是也很明顯,這道題確實是讓我們找最值的,問題出在哪呢?
問題出在,這道題其實是讓我們求極小值和極大值
的,也即先找出一個波段內的極小值和極大值,然後如果發現另一個更小的極小值後
,再找出從此極小值開始後的極大值;最終我們比較的是這些極大值和極小值的差中的最大值。
class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0, temMax = 0, minprice = Integer.MAX_VALUE;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice) { //一旦找到更小的值,則開始從此點找極大值
minprice = prices[i]; //始終存的的是已發現的最小值
temMax = 0;//重新開始計算差值(這一步是可以忽略的)
} else {
temMax = prices[i] - minprice;
maxprofit = Math.max(maxprofit, temMax);//和之前的最大利潤做比較
}
}
return maxprofit;
}
}
優化
以上邏輯等價於如下形式:
class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0, minprice = Integer.MAX_VALUE;
for (int price : prices) {
if (price < minprice) { //一旦找到更小的值,則開始從此點找極大值
minprice = price; //始終存的的是已發現的最小值
} else {
maxprofit = Math.max(maxprofit, price - minprice);//和之前的最大利潤做比較
}
}
return maxprofit;
}
}
也等價於如下形式,雖然這種形式程式碼量小了一些,但這種形式其實計算多個很多:
class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0, buy = Integer.MAX_VALUE;
for (int price : prices) {
buy = Math.min(buy, price);
maxprofit = Math.max(maxprofit, price - buy);
}
return maxprofit;
}
}
買賣股票的最佳時機 II -122
陣列 貪心演算法
題目
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
設計一個演算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交易(多次買賣一支股票)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
波峰波谷法
class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0, minprice = Integer.MAX_VALUE, maxprice = Integer.MAX_VALUE;
boolean findMin = true; //找波谷還是波峰
for (int i = 0; i < prices.length; i++) {
if (findMin) { //找波谷
if (prices[i] < minprice) { //有更低的波谷
minprice = prices[i]; //更新購買價格
maxprice = prices[i];
} else { //比波谷的值大,那麼我們就找波峰
maxprice = prices[i]; //更新賣出價格
findMin = false;
}
} else { //找波峰
if (prices[i] > maxprice) { //有更高的波峰
maxprice = prices[i]; //更新賣出價格
} else { //比波峰小,那麼我們就在之前賣出,然後在這裡買入
maxprofit += (maxprice - minprice); //更新收益
minprice = prices[i]; //重置所有狀態
maxprice = prices[i];
findMin = true;
}
}
}
return maxprofit + (maxprice - minprice);//防止最後在找波峰過程中結束,導致沒有賣出的問題
}
}
時間複雜度:O(n)
空間複雜度:O(1)
波峰波谷法優化
上面的程式碼實際上有很多運算時可以忽略的,可以優化為如下邏輯
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length <= 1) return 0;
int i = 0, valley = prices[0], peak = prices[0], maxprofit = 0;
while (i < prices.length - 1) {
while (i < prices.length - 1 && prices[i] >= prices[i + 1]) i++; //有更低的波谷
valley = prices[i]; //更新購買價格
while (i < prices.length - 1 && prices[i] <= prices[i + 1]) i++; //有更高的波峰
peak = prices[i]; //更新賣出價格
maxprofit += peak - valley;
}
return maxprofit;
}
}
累加法
我們不需要跟蹤峰值和谷值對應的成本以及最大利潤,我們可以直接繼續增加陣列的連續數字之間的差值,如果第二個數字大於第一個數字,我們獲得的總和將是最大利潤。這種方法將簡化解決方案。
例如:[1, 7, 2, 3, 6, 7, 6, 7]
與此陣列對應的圖形是:
從上圖中,我們可以觀察到 A+B+C 的和等於差值 D 所對應的連續峰和谷的高度之差。
class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) maxprofit += prices[i] - prices[i - 1];
}
return maxprofit;
}
}
買賣股票的最佳時機 III -123
給定一個數組,它的第 i 個元素是一支給定的股票在第 i 天的價格。
設計一個演算法來計算你所能獲取的最大利潤。你最多可以完成 兩筆 交易
。
注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
動態規劃 二維陣列(不懂)
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length <= 1) return 0;
int n = prices.length;
int[][] g = new int[n][3], l = new int[n][3];
for (int i = 1; i < n; i++) {
int diff = prices[i] - prices[i - 1];
for (int j = 1; j <= 2; j++) {
l[i][j] = Math.max(g[i - 1][j - 1] + Math.max(diff, 0), l[i - 1][j] + diff);
g[i][j] = Math.max(l[i][j], g[i - 1][j]);
}
}
return g[n - 1][2];
}
}
動態規劃 一維陣列(不懂)
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length <= 1) return 0;
int n = prices.length;
int[] g = new int[3], l = new int[3];
for (int i = 0; i < n - 1; i++) {
int diff = prices[i+1] - prices[i ];
for (int j = 2; j >= 1; j--) {
l[j] = Math.max(g[j - 1] + Math.max(diff, 0), l[j] + diff);
g[j] = Math.max(l[j], g[j]);
}
}
return g[2];
}
}
買賣股票的最佳時機 IV -188
給定一個數組,它的第 i 個元素是一支給定的股票在第 i 天的價格。
設計一個演算法來計算你所能獲取的最大利潤。你最多可以完成 k 筆交易
。
注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
方法宣告
class Solution {
public int maxProfit(int k, int[] prices) {
}
}
動態規劃(不懂)
class Solution {
public int maxProfit(int k, int[] prices) {
if (prices == null || prices.length <= 1) return 0;
int n = prices.length;
if (k >= n) return maxProfit(prices);
int[] g = new int[k + 1], l = new int[k + 1];
for (int i = 0; i < n - 1; i++) {
int diff = prices[i + 1] - prices[i];
for (int j = k; j >= 1; j--) {
l[j] = Math.max(g[j - 1] + Math.max(diff, 0), l[j] + diff);
g[j] = Math.max(l[j], g[j]);
}
}
return g[k];
}
public int maxProfit(int[] prices) {
int maxprofit = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) maxprofit += prices[i] - prices[i - 1];
}
return maxprofit;
}
}
2018-12-16