1. 程式人生 > >【LeetCode & 劍指offer刷題】動態規劃與貪婪法題4:42 連續子陣列的最大和(53. Maximum Subarray)

【LeetCode & 劍指offer刷題】動態規劃與貪婪法題4:42 連續子陣列的最大和(53. Maximum Subarray)

【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...)

53. Maximum Subarray

Given an integer array   nums , find the contiguous subarray (containing at least one number) which has the largest sum and return its sum. Example: Input:
[-2,1,-3,4,-1,2,1,-5,4], Output: 6 Explanation: [4,-1,2,1] has the largest sum = 6. Follow up: If you have figured out the O(n ) solution , try coding another solution using the divide and conquer approach,
which is more subtle.     // 最大子陣列問題   /* 方法:動態規劃 f(i) = a[i], i <0或f(i-1) <= 0; f(i) = f(i-1) + a[i], i!=0, f(i-1) > 0 max(f[i]) 不太好想
*/     /* 方法一:動態規劃 sum代表了包含nums[i]時(以nums[i]結尾的子陣列)的最大和 不斷更新sum和res   sum = max(sum + num, num) 分析:時間複雜度 O n ( 線性 ) */ class Solution { public :     int maxSubArray ( vector < int >& nums )     {         int res = INT_MIN , sum = 0 ;         for ( int num : nums )         {             sum = max(sum + num, num);             res = max(res, sum);         }         return res ;     } };   // 方法二:分治法 // 具體過程:將陣列分為左子陣列、右子陣列、跨越中點的子陣列問題 // 分析:時間複雜度 O(nlgn) //參考資料:《演算法導論》 class Solution { public :     int maxSubArray ( vector < int >& a )     {         return findMaxSubArray ( a , 0 , a . size ()- 1 ); // 遞迴入口     }         // 遞迴函式:找 a[left...right] 的最大子陣列(歸併排序和快速排序中也用到了分治法,可以類比一下)     int findMaxSubArray ( vector < int >& a , int left , int right ) // 遞迴函式     {         if ( right == left ) return a [ left ];                 int mid = ( left + right )/ 2 ;         int left_sum = findMaxSubArray ( a , left , mid );         int right_sum = findMaxSubArray ( a , mid + 1 , right );         int cross_sum = findMaxCrossingSubArray ( a , left , mid , right );         return max ( max ( left_sum , right_sum ), cross_sum );             }     // 找跨中點的最大子陣列,我們只需找出形如 A[i.. mid] A[mid+ 1. .j] 的最大子陣列,然後將其合併即可。     int findMaxCrossingSubArray ( vector < int >& a , int left , int mid , int right )     {         int left_sum , sum , right_sum ;         sum = 0 ;         left_sum = a [ mid ]; // 初始化為參與計算的第一個元素           for ( int i = mid ; i >= left ; i --) //從中間往左邊遍歷         {             sum += a [ i ];             if ( sum > left_sum ) left_sum = sum ;         }                 sum = 0 ;         right_sum = a [ mid + 1 ]; // 初始化         for ( int j = mid + 1 ; j <= right ; j ++)  //從中間往右邊遍歷         {             sum += a [ j ];             if ( sum > right_sum ) right_sum = sum ;         }         return ( left_sum + right_sum );                     } };