劍指offer.63題 股票的最大利潤 經典dp問題求解與優化
阿新 • • 發佈:2020-12-27
技術標籤:Leetcode動態規劃leetcode演算法java
文章目錄
一、題目描述
本文所講解的是劍指offer第63題——股票的最大利潤,本題是一個經典的dp動態規劃問題。
示例 1: 輸入: [7,1,5,3,6,4] 輸出: 5 解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣 出,最大利潤 = 6-1 = 5 。 注意利潤不能是 7-1 = 6, 因為賣出價格需要大於買入價格。 示例 2: 輸入: [7,6,4,3,1] 輸出: 0 解釋: 在這種情況下, 沒有交易完成, 所以最大利潤為 0。
二、貪心法
思路:新建一個與原來prices長度一致的陣列Matrix,用於記錄該天買入股票能夠獲得的最大收益。然後依次遍歷當天之後最高的價格,並將該價格保存於陣列Matrix中。
class Solution {
public int maxProfit(int[] prices) {
if(prices.length==0)
return 0;
int Matrix[]=new int[prices.length];
int max;
int length=Matrix.length;
for (int i=length-2;i>=0;i--)
{
max=findMax(prices,i+1,length);
Matrix[i]=(prices[i]>=prices[max])?0:(prices[max]-prices[i]);
}
max=0;
for(int i=0;i<length;i++)
{
if(Matrix[i]>Matrix[max])
max=i;
}
return Matrix[max];
}
public int findMax(int []prices,int start,int end)
{
int max=start;
for(int i=start+1;i<end;i++)
{
if(prices[i]>prices[max])
max=i;
}
return max;
}
}
三、動態規劃方法
-
狀態定義: 設動態規劃列表 dp,dp[i]代表以 prices[i] 為結尾的子陣列的最大利潤(以下簡稱為 前 i日的最大利潤 )。
-
轉移方程: 由於題目限定 “買賣該股票一次” ,因此前 i 日最大利潤 dp[i] 等於前 i - 1 日最大利潤 dp[i-1] 和第 i 日賣出的最大利潤中的最大值。
前i日最大利潤=max(前(i−1)日最大利潤,第i日價格−前i日最低價格)
即:
dp[i] = max(dp[i - 1], prices[i] - min(prices[0:i]))
- 初始狀態: dp[0] = 0,即首日利潤為 0 ;
- 返回值: dp[n - 1],其中 n 為 dp 列表長度。
程式碼如下所示:
class Solution {
public int maxProfit(int[] prices) {
if(prices.length==0)
return 0;
int dp[]=new int[prices.length];
int min=0;
for(int i=1;i<prices.length;i++) {
dp[i]=Math.max(dp[i-1],prices[i]-prices[min]);
if(prices[i]<prices[min])
min=i;
}
int max=0;
for(int i=0;i<dp.length;i++)
if(dp[i]>dp[max])
max=i;
return dp[max];
}
}
其中,min用於表示當前迴圈到的日期之前的最低價格。
從上圖的提交記錄也可以看出,採用動態規劃後,演算法執行時間有了質的提升。
四、狀態轉移方程的優化
效率優化,以下為Leetcode官方解法中的概述:
時間複雜度降低: 前 i 日的最低價格min(prices[0:i]) 時間複雜度為 O(i)。而在遍歷 prices 時,可以藉助一個變數(記為成本 cost )每日更新最低價格。優化後的轉移方程為:
dp[i]=max(dp[i−1],prices[i]−min(cost,prices[i]))
空間複雜度降低: 由於 dp[i] 只與 dp[i - 1], prices[i] , cost 相關,因此可使用一個變數(記為利潤 profit)代替 dp 列表。優化後的轉移方程為:
profit=max(profit,prices[i]−min(cost,prices[i]))
複雜度分析:
時間複雜度 O(N): 其中 N 為 prices 列表長度,動態規劃需遍歷 pricesprices 。
空間複雜度 O(1) : 變數 cost和 profit使用常數大小的額外空間。
class Solution {
public int maxProfit(int[] prices) {
int cost = Integer.MAX_VALUE, profit = 0;
for(int price : prices) {
cost = Math.min(cost, price);
profit = Math.max(profit, price - cost);
}
return profit;
}
}