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).

浙公网安备 33010602011771号