線性dp:LeetCode122.買賣股票的最佳時機ll

Tomorrowland_D發表於2024-09-10

買賣股票

  • 本文所講解的內容與LeetCode122. 買賣股票的最佳時機ll,這道題題意相同,閱讀完本文後可以自行挑戰一下
  • 力扣連結

題目敘述:

給定一個長度為N的陣列,陣列中的第i個數字表示一個給定股票在第i天的價格。

設計一個演算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交易(多次買賣一支股票)。

注意:你不能同時參與多筆交易(你必須在再次購買前出售掉悠前的股票)。一次買入賣出合為一筆交易。

輸入格式:

第一行包含整數 N,表示天數。第二行包含N個不大於10000的正整數表示每天股票的價格。

輸出格式

輸出一個整數,表示最大利潤。

輸入樣例1

6
7 1 5 3 4 6

輸出樣例1

7

輸入樣例2

5
7 6 4 3 1

輸出樣例2

0

樣例解釋:

  • 樣例1:在第2天買入,在第3天賣出,這筆交易所能獲得利潤=5-1=4。隨後在第4天買入,在第6天賣出,這筆交易所能獲得利潤=6-3=3。共得利潤4+3 =7
  • 樣例2:在這種情況下,不進行任何交易,所以最大利潤為 0。

動態規劃思路講解:

  • 我們分析總利潤可知,總利潤是關於天數i 的函式,並且在第i天的時候,只有兩種狀態與之對應
    • 1.手中無票:dp[i][0]
    • 2.手中有票:dp[i][1]
  • 所以說我們可以設定dp[i][0],dp[i][1] 為狀態變數,然後進行狀態的轉移,最終得出我們需要的答案。

1.狀態變數的含義

  • dp[i][0]表示第i天,手中無票時能夠獲取的最大利潤
  • dp[i][1]表示第i天,手中有票時能夠獲取的最大利潤

2. 遞推公式

  • 我們可以使用帶權的有向圖來生動的理解這個過程,我們要知道遞推公式,就要了解狀態轉移的那個過程,也就是我們當前的狀態是由以前的哪些狀態推導而來。

      1. dp[i][0]表示第i天,手中無票時能獲取的最大利潤,我們可以透過dp[i-1][0]dp[i-1][1] ,也就是第i-1天,手中有票或者手中無票這兩個狀態推導而來,如果是第i-1天手中無票,那麼表示沒有發生交易,那麼dp[i][0]=dp[i-1][0] ,反之,從i-1天有票到第i天無票,那麼意味著我們在第i天賣掉了股票,此時dp[i][0]=dp[i-1][1]+w[i] ,由於我們是取最大利潤,所以說是取二者的最大值,即:
      dp[i][0]=max(dp[i-1][0],dp[i-1][1]+w[i]);
      
      1. dp[i][1] 也是同理,跟上面的推導方式差不多,所以我就不在贅述了
      dp[i][1]=max(dp[i-1][1],dp[i-1][0]-w[i]);
      
  • 所以說,總的遞推公式如下:

dp[i][0]=max(dp[i-1][0],dp[i-1][1]+w[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-w[i]);

3.如何初始化?

  • 我們由這個遞推公式,如何初始化邊界條件呢?
  • 假設我們從第1天開始,到第n天結束,那麼我們第一天的兩個狀態就是邊界條件
dp[1][0]=0;		//第1天無票的最大利潤就是0
dp[1][1]=-w[1];  //第1天就有票證明我買了第一天的那個股票

4. 遍歷順序

  • 由遞推公式可知,我們的狀態變數dp[i][0],dp[i][1]取決於dp[i-1][0],dp[i-1][1] 。所以說我們的遍歷順序是從前到後進行遍歷。

5. 舉例列印dp陣列

  • 在本題,讀者可以自行在for迴圈內進行插入printf語句進行驗證我們dp陣列的正確性

程式碼:

#include<iostream>
#include<cstring>
using namespace std;
const int N = 100010;
int w[N],dp[N][2];
int n;

int main(){
  scanf("%d", &n);
  for(int i=1;i<=n;i++) scanf("%d",&w[i]); 
     
  dp[1][0]=0; dp[1][1]=-w[1];
  for(int i=2; i<=n; ++i){
    dp[i][0]=max(dp[i-1][0],dp[i-1][1]+w[i]);    
    dp[i][1]=max(dp[i-1][1],dp[i-1][0]-w[i]);
  }
    //第n天的時候,手中無票一定是利潤最大,所以說不用取二者最大值了。
  cout<<dp[n][0];
}

LeetCode122的參考程式碼

class Solution {
public:
	int maxProfit(vector<int>& prices) {
		vector<vector<int> > dp(prices.size(),vector<int>(2));
        //進行初始化條件
		dp[0][0] = 0;
		dp[0][1] = -prices[0];
		for (int i = 1; i < prices.size(); i++) {
			dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
			dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
		}
		return dp[prices.size() - 1][0];
	}
};

相關文章