1. 程式人生 > 實用技巧 >2.14 求陣列的子陣列之和的最大值

2.14 求陣列的子陣列之和的最大值

2.14 求陣列的子陣列之和的最大值

基本問題:一個有N個正整數元素的一維陣列,這個陣列有很多子陣列,那麼子陣列之和的最大值是什呢嗎?

解法:
解法 : 動態規劃

動態規劃
狀態定義 : dp[i] 表示包含第i個元素的最大子序和
狀態轉移方程:dp[i] = max{dp[i-1] + arr[i] , arr[i]}
初始狀態:dp[0] = nums[0];

拓展問題:

  • 1 如果陣列[A[0], ...,A[n-1]]首尾相連,題目又該如何解釋?
  • 2 如果題目要求同時返回最大子陣列的位置,演算法應該如何改變?還能保持\(O(n)\)的時間複雜度麼?

all coding

// 2.14 求陣列的子陣列之和的最大值
class Test{
	public static void main(String[] args) {
		/**
		基本問題:一個有N個正整數元素的一維陣列,這個陣列有很多子陣列,那麼子陣列之和的最大值是什呢嗎?
		解法:
            解法 : 動態規劃
        */
		int[] arr = new int[]{1,-2,3,5,-3,2};
        print(arr);
		System.out.println(maxSubArray2(arr));
        print(maxSubArrayPos(arr));
	}
    public static void print(int[] arr){
        for(int i:arr) System.out.print(i+" ");
        System.out.println();
    }
    /**
    動態規劃
        狀態定義
            dp[i] 表示包含第i個元素的最大子序和
        狀態轉移方程
            dp[i] = max{dp[i-1] + arr[i] , arr[i]}
        初始狀態:
            dp[0] = nums[0];
    */
	public static int maxSubArray(int[] nums) {
        if(nums==null || nums.length==0) return 0;
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for(int i = 1;i <nums.length;i++){
            dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);
        }
        int res = Integer.MIN_VALUE;
        for(int num:dp) res = Math.max(num,res);

        return res;
    }
    /**
    拓展問題:
        1 如果陣列[A[0], ...,A[n-1]]首尾相連,題目又該如何解釋?
        2 如果題目要求同時返回最大子陣列的位置,演算法應該如何改變?還能保持$O(n)$的時間複雜度麼?
    */
    /**
    拓展問題1:
    */
    public static int maxSubArray2(int[] nums) {
        if(nums==null || nums.length==0) return 0;
        int[] dp = new int[nums.length*2];
        dp[0] = nums[0];
        for(int i = 1;i <nums.length*2;i++){
            dp[i] = Math.max(dp[i-1]+nums[i%nums.length],nums[i%nums.length]);
        }
        int res = Integer.MIN_VALUE;
        for(int num:dp) res = Math.max(num,res);

        return res;
    }
    /**
    拓展問題2:
    return [start,end]
    */

    public static int[] maxSubArrayPos(int[] nums){
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for(int i = 1;i <nums.length;i++){
            dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);
        }
        int max = Integer.MIN_VALUE;
        for(int num:dp) max = Math.max(max,num);
        int[] res = new int[2];
        for(int i = 0;i<dp.length;i++) if(dp[i] == max) res[1] = i;
        int start;
        for(start= res[1];max!=0;start--) max-=nums[start];
        res[0] = start-1;
        return res;  
    }
	
}