????????在動態規劃中,填表時固定最后一個數還是倒數第二個數,取決于問題的定義和狀態轉移方程的設計。
目錄
1. 固定最后一個數
適用場景
特點
示例
2. 固定倒數第二個數
適用場景
特點
示例
3. 固定最后一個數與倒數第二個數的對比
4. 總結
1. 固定最后一個數
適用場景
-
當問題的解與以某個位置為結尾的子問題相關時,通常固定最后一個數。
-
例如:最大子數組和、最長遞增子序列(LIS)等問題。
特點
-
狀態定義通常為?
dp[i]
,表示以第?i
?個元素為結尾的最優解。 -
狀態轉移方程通常依賴于前一個狀態(
dp[i-1]
)或前面所有狀態。
示例
-
最大子數組和
狀態定義:dp[i]
?表示以?nums[i]
?為結尾的最大子數組和。
狀態轉移:dp[i] = max(nums[i], dp[i-1] + nums[i])
代碼:int maxSubArray(vector<int>& nums) {int dp = nums[0], res = dp;for (int i = 1; i < nums.size(); i++) {dp = max(nums[i], dp + nums[i]);res = max(res, dp);}return res; }
-
最長遞增子序列(LIS)
狀態定義:dp[i]
?表示以?nums[i]
?為結尾的最長遞增子序列長度。
狀態轉移:dp[i] = max(dp[i], dp[j] + 1)
,其中?j < i
?且?nums[j] < nums[i]
代碼:int lengthOfLIS(vector<int>& nums) {vector<int> dp(nums.size(), 1);int res = 1;for (int i = 1; i < nums.size(); i++) {for (int j = 0; j < i; j++) {if (nums[i] > nums[j]) {dp[i] = max(dp[i], dp[j] + 1);}}res = max(res, dp[i]);}return res; }
2. 固定倒數第二個數
適用場景
-
當問題的解與子問題的中間狀態相關時,通常固定倒數第二個數。
-
例如:最長公共子序列(LCS)、編輯距離等問題。
特點
-
狀態定義通常為?
dp[i][j]
,表示前?i
?個元素和前?j
?個元素之間的某種關系。 -
狀態轉移方程通常依賴于?
dp[i-1][j-1]
、dp[i-1][j]
?或?dp[i][j-1]
。
示例
-
最長公共子序列(LCS)
狀態定義:dp[i][j]
?表示字符串?A
?的前?i
?個字符和字符串?B
?的前?j
?個字符的最長公共子序列長度。
狀態轉移:if (A[i-1] == B[j-1]) {dp[i][j] = dp[i-1][j-1] + 1; } else {dp[i][j] = max(dp[i-1][j], dp[i][j-1]); }
代碼:
int longestCommonSubsequence(string text1, string text2) {int m = text1.size(), n = text2.size();vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (text1[i-1] == text2[j-1]) {dp[i][j] = dp[i-1][j-1] + 1;} else {dp[i][j] = max(dp[i-1][j], dp[i][j-1]);}}}return dp[m][n]; }
-
編輯距離
狀態定義:dp[i][j]
?表示將字符串?A
?的前?i
?個字符轉換為字符串?B
?的前?j
?個字符所需的最小操作次數。
狀態轉移:if (A[i-1] == B[j-1]) {dp[i][j] = dp[i-1][j-1]; } else {dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1; }
代碼:
int minDistance(string word1, string word2) {int m = word1.size(), n = word2.size();vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));for (int i = 0; i <= m; i++) dp[i][0] = i;for (int j = 0; j <= n; j++) dp[0][j] = j;for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (word1[i-1] == word2[j-1]) {dp[i][j] = dp[i-1][j-1];} else {dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1;}}}return dp[m][n]; }
3. 固定最后一個數與倒數第二個數的對比
特性 | 固定最后一個數 | 固定倒數第二個數 |
---|---|---|
適用問題 | 子數組、子序列問題 | 雙序列、矩陣類問題 |
狀態定義 | dp[i] ?或?dp[i][j] | dp[i][j] |
狀態轉移 | 依賴前一個狀態或前面所有狀態 | 依賴?dp[i-1][j-1] ?等中間狀態 |
典型問題 | 最大子數組和、LIS | LCS、編輯距離 |
4. 總結
-
固定最后一個數:適用于子數組或子序列問題,狀態轉移通常依賴于前一個狀態或前面所有狀態。
-
固定倒數第二個數:適用于雙序列或矩陣類問題,狀態轉移通常依賴于中間狀態(如?
dp[i-1][j-1]
)。