一直對動態規劃的題有種恐懼,每當做這類題的時候,總是感覺無從下手,思考一會就放棄了,然後去評論區貫徹我的拿來主義,到頭來還是沒真正搞懂。沒辦法,戰勝恐懼的最好辦法就是面對恐懼。目前只能用最淺顯的理解去解答這類題目,包括之前的秋葉收藏集,又何嘗不是呢?
給定一個陣列,它的第 i 個元素是一支給定股票第 i 天的價格。如果你最多隻允許完成一筆交易(即買入和賣出一支股票一次),設計一個演算法來計算你所能獲取的最大利潤。注意:你不能在買入股票前賣出股票。
思路
首先,最直觀的理解:當遍歷整個陣列的時候,每到一個位置,就去判斷一下當前股票如果賣出的話的利潤,然後更新最大值。而為了保持利潤的最大值,應該記錄到當前i位置的最小值(不包括當前 i ),以此作為買入。
程式碼如下:
public int maxProfit(int[] prices) {
if (prices.length <= 1) {
return 0;
}
int min = prices[0]; //初始化為陣列首元素
int max = 0;
for (int i = 1; i < prices.length; i++) {
max = Math.max(max, prices[i] - min); //如果當前賣出
min = Math.min(min, prices[i]); //更新最小值
}
return max;
}
難度簡單
給定一個陣列,它的第 i 個元素是一支給定股票第 i 天的價格。
設計一個演算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交易(多次買賣一支股票)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
思路
採用動態規劃,每當到一個 i 位置的時候無非就兩種狀態——持有股票和不持有股票,所以每一個狀態都可以由上一狀態決定
程式碼如下:
public int maxProfit(int[] prices) {
if (prices.length <= 1) {
return 0;
}
int len = prices.length;
int[][] dp = new int[len][2]; //dp[i][0] 表示第i天不持有,dp[i][1]表示第i天持有
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[len - 1][0];
}
給定一個陣列,它的第 i 個元素是一支給定的股票在第 i 天的價格。
設計一個演算法來計算你所能獲取的最大利潤。你最多可以完成 兩筆 交易。
注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
思路
由於限制了交易次數,故不能向上一題一樣無限次交易,此時需要記錄交易次數這個狀態。
程式碼如下:
public int maxProfit(int[] prices) {
if (prices.length <= 1) {
return 0;
}
int k = 2;
int[][][] dp = new int[prices.length][k + 1][2];
for (int i = 0; i < prices.length; i++) {
for (int j = k; j > 0; j--) {
if (i == 0) {
//第i天,還有j次,手裡沒有股票,當i=0,手裡沒股票,最大利潤為0
dp[0][j][0] = 0;
dp[0][j][1] = -prices[0];
continue;
}
//今天手裡沒股票,比較MAX(前一天可能沒股票,前一天有股票但是今天賣出去了,賣出去就有利潤,所以+ prices[i])
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
//今天手裡有股票,比較MAX(前一天可能有股票,前一天沒股票但是今天買了,買了就有成本,所以- prices[i])
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
}
}
return dp[prices.length - 1][k][0];
}
給定一個陣列,它的第 i 個元素是一支給定的股票在第 i 天的價格。
設計一個演算法來計算你所能獲取的最大利潤。你最多可以完成 k 筆交易。
注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
思路
此題同上,只不過需要判斷一下k的大小,進而轉換為無限次交易或者交易指定次數
public int maxProfit(int k, int[] prices) {
if (prices.length <= 1) {
return 0;
}
int n = prices.length;
//當k非常大時轉為無限次交易
if(k>=n/2) {
int dp0=0,dp1=-prices[0];
for(int i=1;i<n;++i) {
int tmp = dp0;
dp0 = Math.max(dp0,dp1+prices[i]);
dp1 = Math.max(dp1,dp0-prices[i]);
}
return Math.max(dp0,dp1);
}
int[][][] dp = new int[prices.length][k + 1][2];
for (int i = 0; i < prices.length; i++) {
for (int j = k; j > 0; j--) {
if (i == 0) {
//第i天,還有j次,手裡沒有股票,當i=0,手裡沒股票,最大利潤為0
dp[0][j][0] = 0;
dp[0][j][1] = -prices[0];
continue;
}
//今天手裡沒股票,比較MAX(前一天可能沒股票,前一天有股票但是今天賣出去了,賣出去就有利潤,所以+ prices[i])
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
//今天手裡有股票,比較MAX(前一天可能有股票,前一天沒股票但是今天買了,買了就有成本,所以- prices[i])
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
}
}
return dp[prices.length - 1][k][0];
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結