算法优化:最大字段和,双指针遍历(n^2),分治法(nlogn),动态规划(n)
生活随笔
收集整理的這篇文章主要介紹了
算法优化:最大字段和,双指针遍历(n^2),分治法(nlogn),动态规划(n)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最大字段和,有點類似與最長公共子序列,這里是求連續一段求和最大的一段,比如[-2,11,-4,-4,13,-5,-2]最大求和的連續一段為11,-4,-4,13,和為16.
最基本的雙針模型遍歷,兩個指針,分別代表最大和序列的起始和終止,算法時間復雜度O(n^2)
# 以下算法時間復雜度O(n^2) def maxSum(arr):num = len(arr)# 記錄最好的結果,這個結果是一個不斷逼近的過程best_result_start =0best_result_end=0best_result =0# i為起始的指針,j為終止的指針,基于簡單計算,起始位置不可能為負的,因為假如# 為負的,后移一位就會使結果變大for i in range(num):if arr[i] <0:continueelse:cur_sum = arr[i]# j指針后移更新當前的求和for j in range(i+1,num):cur_sum +=arr[j] # 假如當前求和大于當前的最好結果,就更新當前的最好結果if cur_sum > best_result:best_result = cur_sumbest_result_start =ibest_result_end = jreturn best_result,best_result_start,best_result_end分治的算法:分成2段,3中情況考慮,取其最大,算法時間復雜度O(nlogn)之間
#%% # 基于分治的做法,把數組分成兩個部分,最優解出現的情況:要么在左半邊,要么在右半邊, # 左邊的尾部+右邊頭部 # 針對起始為left,求最長字段和并返回,終止的標號 def start_max(arr,left,right):cur_sum =0best_result =0best_result_end =0for i in range(left,right+1):cur_sum += arr[i] if cur_sum > best_result:best_result = cur_sumbest_result_end = ireturn best_result,best_result_end# 針對起始為right,求最長字段和并返回,終止的標號 def end_max(arr,left,right):cur_sum =0best_result =0best_result_end =0for i in range(right,left-1,-1):cur_sum += arr[i] if cur_sum > best_result:best_result = cur_sumbest_result_end = ireturn best_result,best_result_end # 遞歸的理解,一種直接看成遞歸到最底層,然后在最底層的處理,一種直接看成某一層直接把遞歸函數看成 # 你要用的變量 # 關于return和不return的理解,當你需要返回結果的時候就需要返回,在原來數組上操作的情況就可以不返回 def maxSumSub(arr,left,right):# 遞歸的出口,也就是最小子問題的解if left == right:best_sum = max(0,arr[left])best_i = leftbest_j = rightelse:# 劃分子問題的過程,一層層進入遞歸,子問題不斷劃分,dividemid = left + (right-left)//2# 針對子問題處理,此時三個子問題# 最優解在左邊left_max,left_i,left_j = maxSumSub(arr,left,mid)# 最優解在右邊right_max,right_i,right_j = maxSumSub(arr,mid+1,right)# 最優解出現在左邊的尾部+右邊頭部,最優解和起止位置best_left,best_i = end_max(arr,left,mid)best_right,best_j =start_max(arr,mid+1,right)best_sum = best_left+ best_right# 最優解取三者中的最大值if best_sum < left_max:best_sum = left_maxbest_i = left_ibest_j = left_j if best_sum < right_max:best_sum = right_maxbest_i = right_ibest_j = right_j return best_sum,best_i,best_j動態規劃實現,狀態方程為:b[j] = max{b[j-1]+arr[j],arr[j]},b[j]為終點為j的最大字段和,原問題最優解就是b[j]的最大值,明顯這個是O(n)的時間復雜度。還是有必要說明一下,這里的 動態規劃并沒有對原問題進行動態規劃,而是對原問題的某個解進行動態規劃,或者說原問題的動態規劃方程為max{max{b[j-1]+arr[j],arr[j]}}
#%% # 動態規劃的算法,狀態方程,初始值 # 如何劃分子問題比較好了,看成選擇問題,選與不選,從尾部開始,i選的話,最大值就是end_max前面 # n-1個元素的最大值+arr[i],不選的話就是前面n-1個元素求最小字段和 # 這個工作量好大,問題規模縮小了1,然后干了分治算法一層的工作量 # 所以這種規約子問題的方案不好? # 最大字段結束在j,那么原問題的解就是j=0,1,2..len(arr)-1 # 這么多情況里面的最大值, # 我們定義b[j]為結束在j字段和最大值,max{b[j]} 0<=j<=len(arr)-1 # 我們只要求出了每一個b[j],最大值就是可以從里面求出來了 # 那么b如何求解了,結束在j的最大字段和,假如前面j-1最大字段和小于0的話,那就是arr[j] # 狀態方程為:b[j] = max{b[j-1]+arr[j],arr[j]} # 這里不需要考慮arr[j]是否大于0,因為我的子問題就是定義的是結束在j的最大字段和,至于 # 最終的解是結束在不同的j上的最大字段和的最大值。# 這個方法可以知道結束位置j,沒法知道起始位置i為多少啊 def maxSumDynamicProgramming(arr):# 本來是需要一個數組來記錄b的,然后找b[]里面的最大值# 但是我們得到一個b,就可以更顯最優結果的,我只要記錄當前最優解就行了,所以只需要當前的b# b的初值就是b[0-1]的值,也就是沒有元素時最大字段和為多少,為0cur_b =0# 用于記錄最優的結果best_result = 0best_j = -1# 根據狀態方程自底向上完成for j in range(len(arr)):# b[j] = max{b[j-1]+arr[j],arr[j]},當b[j-1]>0為左邊,否則為右邊,也可以直接用maxif cur_b>0:cur_b += arr[j]else:cur_b = arr[j]# 每求出一個b,就更新一下當前最優解if cur_b >= best_result:best_result = cur_bbest_j = jreturn best_result,best_j總結
以上是生活随笔為你收集整理的算法优化:最大字段和,双指针遍历(n^2),分治法(nlogn),动态规划(n)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分治法:BFPTR算法找第k小
- 下一篇: 算法优化:最大子段和,最大子矩阵和,一维