maximum-sum-subarray
給定一個整數數組 nums
,找到一個具有最大和的連續子數組(子數組最少包含一個元素),返回其最大和。
看到一個形象的比喻:
假設你是一個選擇性遺忘的賭徒,數組nums表示你這幾天來贏錢或者輸錢
sum——表示這幾天來的輸贏,
max——存儲你手裏贏到的最多的錢,
如果昨天你手上還是輸錢(sum < 0),你忘記它,明天繼續賭錢;
如果你手上是贏錢(sum > 0), 你記得,你繼續賭錢;
如果一直輸錢,那麼就記得輸的最少的一次min(nums)
算法思想
通常,解答這類題目[a,b,c,d,e]
避免不了遍歷,有如下三種遍歷子串或子序列方式:
-
以某個節點開頭遍歷; 如
[a]
,[a, b]
,[ a, b, c]
…適用於暴力解法
-
基於長度遍歷;如先遍歷出子序列長度爲 1 的子序列,在遍歷出長度爲 2 的 等等。
-
以子序列的結束節點爲基準遍歷;如
b
爲結束點的所有子序列:[a , b]
[b]
——DP核心
-
暴力法**(空間複雜度O(1),時間複雜度O())
注意邊界條件
for i in range(1,n): sum_=nums[i] for j in range(i+1,n): max_=max(max_,sum_) sum_+=num[j]
-
貪心法(空間複雜度O(1),時間複雜度O())
從左向右迭代,一個個數字加過去,若sum<0,重新開始找字符串
sum_=max_=nums[0] for i in range(1,len(nums)): if sum_<0: sum_=nums[i] max_=max(max_,sum_) else: sum_+=nums[i] max_=max(max_,sum_) print(max_)
-
分治法(空間複雜度O(1),時間複雜度O())
-
問題特徵
-
問題規模縮小到一定程度可容易解決
-
問題可分解爲若干規模較小的相同問題,即該問題具有最優子結構性質
-
子問題的解可合併爲該問題的解
注:分治法完全取決於條件3。若不滿足,則考慮使用DP或貪心
-
子問題相互獨立,即互相之間不包含公共子問題
注:若不獨立,分治法需要多次重複求解公共子問題,故動態規劃較好。
-
-
步驟:
- 分解:將原問題分解爲若干規模較小,互相獨立,和原問題形式相同的子問題
- 解決:若子問題規模較小,直接解決,否則遞歸求解各個子問題
- 合併:將各個子問題的解合併爲原問題的解。
Divide-and-Conquer(P) 1. if |P|≤n0 #|P|:問題P的規模,n0閾值,當規模<閾值時,問題可直接解出,不必分解。 2. then return(ADHOC(P)) #ADHOC(P)基本子算法 3. 將P分解爲較小的子問題 P1 ,P2 ,...,Pk 4. for i←1 to k 5. do yi ← Divide-and-Conquer(Pi) △ 遞歸解決Pi 6. T ← MERGE(y1,y2,...,yk) △ 合併子問題 7. return(T)
-
問題解決(最大序列和)
子問題不相互獨立,重複求解公共問題
'''將序列一分爲2,其最大子序列和不是在序列左邊,便是在其右邊,或跨中間 跨中間單獨考慮:用貪心法來解決 ''' class Solution: def maxSubArray(self, nums: list) -> int: if len(nums)==1: return nums[0] else: mid=len(nums)//2 max_l=self.maxSubArray(nums[0:mid]) max_r=self.maxSubArray(nums[mid:len(nums)]) #跨中心 leftmax=nums[mid-1] sum_l=0 for i in range(mid-1,-1,-1): sum_l+=nums[i] leftmax=max(sum_l,leftmax) rightmax=nums[mid] sum_r=0 for i in range(mid,len(nums)): sum_r+=nums[i] rightmax=max(sum_r,rightmax) max_mid=leftmax+rightmax return max(max_l,max_r,max_mid)
-
-
動態規劃(空間複雜度O(),時間複雜度O())
dp[i]表示nums中以nums[i]爲結尾的最大子序和
dp[i]=max(dp[i-1]+num[i],num[i]);
dp=[nums[0]] for i in range(1,len(nums)): dp.append(max(dp[i-1]+nums[i],nums[i])) return max(dp) #另一種寫法:空間複雜度變爲O(1) max_=sum_=nums[0] for i in range(1,len(nums)): if sum_+nums[i]>nums[i]: sum_+=nums[i] else: sum_=nums[i] max_=max(max_,sum_) return max_