本文正在參加「Python主題月」,詳情查看 活動連接html
這是 LeetCode 上的 劍指 Offer 42. 連續子數組的最大和 ,難度爲 簡單。git
Tag : 「線性 DP」github
輸入一個整型數組,數組中的一個或連續多個整數組成一個子數組。求全部子數組的和的最大值。數組
要求時間複雜度爲 。markdown
示例1:app
輸入: nums = [-2,1,-3,4,-1,2,1,-5,4]
輸出: 6
解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。
複製代碼
提示:oop
這是一道簡單線性 DP 題。post
定義 爲考慮以 爲結尾的子數組的最大值。優化
不失通常性的考慮 如何轉移。ui
顯然對於 而言,以它爲結尾的子數組分兩種狀況:
最終 爲上述兩種狀況取 便可:
Java 代碼:
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] f = new int[n];
f[0] = nums[0];
int ans = f[0];
for (int i = 1; i < n; i++) {
f[i] = Math.max(nums[i], f[i - 1] + nums[i]);
ans = Math.max(ans, f[i]);
}
return ans;
}
}
複製代碼
Python 3 代碼:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
f = [0] * n
ans = f[0] = nums[0]
for i in range(1, n):
f[i] = max(nums[i], f[i - 1] + nums[i])
ans = max(ans, f[i])
return ans
複製代碼
觀察狀態轉移方程,咱們發現 明確值依賴於 。
所以咱們可使用「有限變量」或者「滾動數組」的方式,將空間優化至 。
Java 代碼:
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int max = nums[0], ans = max;
for (int i = 1; i < n; i++) {
max = Math.max(nums[i], max + nums[i]);
ans = Math.max(ans, max);
}
return ans;
}
}
複製代碼
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] f = new int[2];
f[0] = nums[0];
int ans = f[0];
for (int i = 1; i < n; i++) {
int a = i & 1, b = (i - 1) & 1;
f[a] = Math.max(nums[i], f[b] + nums[i]);
ans = Math.max(ans, f[a]);
}
return ans;
}
}
複製代碼
Python 3 代碼:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
ans = curMax = nums[0]
for i in range(1, n):
curMax = max(nums[i], curMax + nums[i])
ans = max(ans, curMax)
return ans
複製代碼
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
ans = nums[0]
f = [ans, 0]
for i in range(1, n):
a, b = i & 1, (i - 1) & 1
f[a] = max(nums[i], f[b] + nums[i])
ans = max(ans, f[a])
return ans
複製代碼
一個有意思的拓展是,將 加法 替換成 乘法。
題目變成 152. 乘積最大子數組(中等)。
又該如何考慮呢?
一個樸素的想法,仍然是考慮定義 表明以 爲結尾的最大值,但存在「負負得正」取得最大值的狀況,光維護一個前綴最大值顯然是不夠的,咱們能夠多引入一維 做爲前綴最小值。
其他分析與本題同理。
Java 代碼:
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
int[] g = new int[n + 1]; // 考慮前 i 個,結果最小值
int[] f = new int[n + 1]; // 考慮前 i 個,結果最大值
g[0] = 1;
f[0] = 1;
int ans = nums[0];
for (int i = 1; i <= n; i++) {
int x = nums[i - 1];
g[i] = Math.min(x, Math.min(g[i - 1] * x, f[i - 1] * x));
f[i] = Math.max(x, Math.max(g[i - 1] * x, f[i - 1] * x));
ans = Math.max(ans, f[i]);
}
return ans;
}
}
複製代碼
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
int min = 1, max = 1;
int ans = nums[0];
for (int i = 1; i <= n; i++) {
int x = nums[i - 1];
int nmin = Math.min(x, Math.min(min * x, max * x));
int nmax = Math.max(x, Math.max(min * x, max * x));
min = nmin;
max = nmax;
ans = Math.max(ans, max);
}
return ans;
}
}
複製代碼
Python 3 代碼:
class Solution:
def maxProduct(self, nums: List[int]) -> int:
n = len(nums)
g = [0] * (n + 1) # 考慮前 i 個,結果最小值
f = [0] * (n + 1) # 考慮前 i 個,結果最大值
g[0] = f[0] = 1
ans = nums[0]
for i in range(1, n + 1):
x = nums[i - 1]
g[i] = min(x, min(g[i-1] * x, f[i-1] * x))
f[i] = max(x, max(g[i-1] * x, f[i-1] * x))
ans = max(ans, max(f[i], g[i]))
return ans
複製代碼
這是咱們「刷穿 LeetCode」系列文章的第 No.劍指 Offer 42
篇,系列開始於 2021/01/01,截止於起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,咱們將先把全部不帶鎖的題目刷完。
在這個系列文章裏面,除了講解解題思路之外,還會盡量給出最爲簡潔的代碼。若是涉及通解還會相應的代碼模板。
爲了方便各位同窗可以電腦上進行調試和提交代碼,我創建了相關的倉庫:github.com/SharingSour… 。
在倉庫地址裏,你能夠看到系列文章的題解連接、系列文章的相應代碼、LeetCode 原題連接和其餘優選題解。