1. 程式人生 > 其它 >【Leecode 53】最大子序和(Java)

【Leecode 53】最大子序和(Java)

技術標籤:演算法

【題目描述】
給定一個整數陣列 nums ,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。

【樣例示例】

  • 輸入:[-2,1,-3,4,-1,2,1,-5,4]
  • 輸出:6

解釋:連續子陣列 [4,-1,2,1] 的和最大,為 6。

如果你已經實現複雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。

【解題程式碼】

方法一:使用動態規劃

首先對陣列進行遍歷,變數count=0儲存當前最大連續子序列和 ,max=nums[0]為最大值

  • 如果 count> 0,說明 count 對結果有增大效果,則保留count並加上當前的nums[i]
  • 如果 count <= 0,說明 count 不能增大結果,需要捨棄,則 把count 更新為當前的nums[i]
  • 每次比較 count 和 max 的大小,如果count>max,則將max更新為count的值
  • 遍歷結束返回結果

時間複雜度:O(n)


class Solution {
    public int maxSubArray(int[] nums) {
        if(nums.length==0){
            return 0;
        }
        if(nums.length==1){
            return nums[0];
        }
        int count=0,max=nums[0];
        for(int
i=0;i<nums.length;i++){ if(count > 0) { count += nums[i]; } else { count = nums[i]; } max = Math.max(count,max); } return max; } }

在這裡插入圖片描述

方法二:分治法

分治法主要就是分類討論,將陣列分成三部分:
(1)[left, mid]
(2)[mid,mid+1]
(3)[mid+1,right]

連續子序列的最大和主要就是由這三部分裡元素的最大和得到,需要注意的是第二部分是一定會被選取到的,可以從中間向兩邊擴散,擴散到底部選出最大值。

時間複雜度:O(NlogN)

public class Solution {
    public int maxSubArray(int[] nums) {
        int len = nums.length;
        // 特判
        if (len == 0) {
            return 0;
        }
        return maxSubArraySum(nums, 0, len - 1);
    }
    private int maxSubArraySum(int[] nums, int left, int right) {
    	// 陣列只有一個數字情況
        if (left == right) {
            return nums[left];
        }
        int mid = (left + right) >> 1;
        return max3(maxSubArraySum(nums, left, mid),	// 計算左半邊
                maxSubArraySum(nums, mid + 1, right),	// 計算右半邊
                maxCrossingSum(nums, left, mid, right));// 計算中間部分
    }
    
	// 比較左中右三個部分哪個最大
    private int max3(int num1, int num2, int num3) {
        return Math.max(num1, Math.max(num2, num3));
    }
    
    // 計算第二部分中間
   	private int maxCrossingSum(int[] nums, int left, int mid, int right) {
        int sum = 0;
        int leftSum = Integer.MIN_VALUE;
        // 計算以 mid 結尾左半邊的最大的子陣列的和(包含 nums[mid])
        for (int i = mid; i >= left; i--) {
            sum += nums[i];
            if (sum > leftSum) {
                leftSum = sum;
            }
        }
        
        sum = 0;
        int rightSum = Integer.MIN_VALUE;        
        // 計算 mid+1 開始右半邊的最大的子陣列的和(不包含 nums[mid])
        for (int i = mid + 1; i <= right; i++) {
            sum += nums[i];
            if (sum > rightSum) {
                rightSum = sum;
            }
        }
        return leftSum + rightSum;
    }
}

在這裡插入圖片描述

個人感覺第一種比較簡單好理解一點,分治法也不是這道題的最優解。

【程式碼參考】

動態規劃、分而治之(Java、Python)