Solution 3: 最大连续子数组和

问题描述

输入一个整形数组,数组中有正数也有负数。

数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组和的最大值。要求时间复杂度为O(n)。

 

例如,输入的数组为[1, -2, 3, 10, -4, 7, 2, -5],最大子数组为[3, 10, -4, 7, 2],最大子数组和为18.

 

解决思路

一维数组的动态规划, dp[i] 代表至今为止包含下标为i的元素的最大子数组和,假设输入的数组为nums[i],创建与nums数组同大小的辅助数组dp。

dp[i]值的递推公式如下:

(1) i == 0时,dp[i] = nums[i];

(2) i> 0时,dp[i] = Max(nums[i], dp[i - 1] + num[i])。

过程中记录下最大值即可,如果要记录下相应的子数组,只需要记录下最大值对应的下标再倒着推即可。

 

程序

public class MaxSumOfSubarray {
	public int getMaxSum(int[] nums) {
		if (nums == null || nums.length == 0) {
			return 0;
		}

		int len = nums.length;
		int[] dp = new int[len];

		// initialize
		dp[0] = nums[0];
		int max = dp[0];

		for (int i = 1; i < len; i++) {
			if (nums[i] > nums[i] + dp[i - 1]) {
				dp[i] = nums[i];
			} else {
				dp[i] = nums[i] + dp[i - 1];
			}
			max = Math.max(max, dp[i]);
		}

		return max;
	}
	
	// record the subarray with max sum
	public List<Integer> getMaxSumSubarray(int[] nums) {
		List<Integer> res = new ArrayList<Integer>();
		if (nums == null || nums.length == 0) {
			return res;
		}
		
		int len = nums.length;
		int[] dp = new int[len];

		// initialize
		dp[0] = nums[0];
		int max = dp[0], maxIdx = 0;

		for (int i = 1; i < len; i++) {
			if (nums[i] > nums[i] + dp[i - 1]) {
				dp[i] = nums[i];
			} else {
				dp[i] = nums[i] + dp[i - 1];
			}
			if (dp[i] > max) {
				max = dp[i];
				maxIdx = i;
			}
		}
		
		// traversal and find the subarray
		for (int j = maxIdx; j >= 0 && max > 0; j--) {
			res.add(0, nums[j]);
			max -= nums[j];
		}
		
		return res;
	}
}

 

时间/空间复杂度

均为O(n).

posted @ 2015-06-28 19:24  Chapter  阅读(127)  评论(0编辑  收藏  举报