leetcode-53- 最大子序和(maximum subarray)-java
阿新 • • 發佈:2018-11-11
題目及用例
package pid053; /*最大子序和 給定一個整數陣列 nums ,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。 示例: 輸入: [-2,1,-3,4,-1,2,1,-5,4], 輸出: 6 解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。 進階: 如果你已經實現複雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。 */ public class main { public static void main(String[] args) { int[][] testTable = {{-2,1,-3,4,-1,2,1,-5,4},{-1,-2,-3,-4,-1},{7,-6,4,3,1},{-1,6,2,7}}; for (int[] ito : testTable) { test(ito); } } private static void test(int[] ito) { Solution solution = new Solution(); int rtn; long begin = System.currentTimeMillis(); for (int i = 0; i < ito.length; i++) { System.out.print(ito[i]+" "); } System.out.println(); //開始時列印陣列 rtn = solution.maxSubArray(ito);//執行程式 long end = System.currentTimeMillis(); //System.out.println(ito + ": rtn=" + rtn); System.out.println( " rtn=" +rtn); // for (int i = 0; i < ito.length; i++) { // System.out.print(ito[i]+" "); // }//列印結果幾陣列 System.out.println(); System.out.println("耗時:" + (end - begin) + "ms"); System.out.println("-------------------"); } }
解法1(成功,16ms,較快)
速度o(n)
方法就是不斷累加,如果現在的值加到負數,先更新max值
然後加上負數,如果小於0,則初始化為0,否則就不管
如果最後max為0,證明全是負數,則取負數中的最大的那個數
package pid053; class Solution { public int maxSubArray(int[] nums) { int length=nums.length; if(length==0){ return 0; } int totalMax=0; int nowMax=0; for(int i=0;i<length;i++){ int now=nums[i]; if(nowMax==0){//新的開始 if(now>=0){ nowMax=now; continue; } else { continue; } } else {//之前已經有和了 if(now>=0){ nowMax=nowMax+now; continue; } else{//上一個的和暫時結束進入減法模式 if(nowMax>totalMax){//加上負的肯定變小,先更新max值 totalMax=nowMax; } nowMax=nowMax+now; if(nowMax<0){ nowMax=0; } continue; } } } if(nowMax>totalMax){ totalMax=nowMax; } if(totalMax==0){//全為負的情況 totalMax=nums[0]; for(int i=0;i<length;i++){ int now=nums[i]; if(now>totalMax){ totalMax=now; } } } return totalMax; } }
解法2(別人的)
dp演算法,思路和我的一樣,但是很簡潔
class Solution { public: int maxSubArray(vector<int>& nums) { int size=nums.size(); int sum=0; int max=INT_MIN; for(int i=0; i<size; i++){ sum+=nums[i]; if(sum>max){ max=sum; } if(sum<0){ sum=0; } } return max; } };
解法3(別人的)
動態規劃
更加簡潔
程式就是
sum=max(sum,nums[i]);
max_sum=max(sum,max_sum);
int maxSubArray(vector<int>& nums) {
if(nums.empty()) return 0;
int sum=nums[0];
int max=sum;
for(int i=1;i<nums.size();++i){
sum=(sum+nums[i])>nums[i]?(sum+nums[i]):nums[i];
max=sum>max?sum:max;
}
return max;
}
---------------------
解法4(別人的)
分治法:思路:假設陣列下標有效範圍是l到r,將陣列分為左半部分下標為(l,mid-1)和右半部分下標為(mid+1,r)以及中間元素下標為mid,接下來遞迴求出左半部分的最大子序和:left=helper(nums,l,mid-1); 右半部分最大子序和right=helper(nums,mid+1,r);接下來再將左半部分右邊界,右半部分左邊界以及中間元素nums[mid]整合,用了兩個迴圈,先整合左半部分右邊界和中間值,再將整合結果與右半部分左邊界整合得到整合以後的最大子序和max_num,最後返回max_num,left,right的最大值即是要求的最大子序和。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size()==0)return 0;
return helper(nums,0,nums.size()-1);
}
int helper(vector<int>& nums,int l,int r){
if(l>r)return INT_MIN;//注意此處不是返回0,比如{-2,-1},分治以後變為左中右n{},-1,{-2}三部分。左半部分{}應返回INT_MIN,
//因為還要和右半部分的返回值進行比較,最終正確結果返回-1。若左半部分返回0,0>-2,且大於左中右的最大組合值(-1),最終結果返回0,出錯
if(l==r)return nums[l];
int mid=(l+r)/2;
int left=helper(nums,l,mid-1);
int right=helper(nums,mid+1,r);
int t=nums[mid];
int max_num=nums[mid];
for(int i=mid-1;i>=l;i--){
t+=nums[i];
max_num=max(max_num,t);
}
t=max_num;
for(int i=mid+1;i<=r;i++){
t+=nums[i];
max_num=max(max_num,t);
}
return max(max(left,right),max_num);
}
};