问题描述
输入一个整形数组,数组中有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组和的最大值。要求时间复杂度为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).