- 题目
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。
- 示例
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
- 动态规划算法
- dp[i]表示以nums[i]为结尾的连续子数组的最大和
- 以nums[i]为结尾的连续子数组的最大和有两种情况
情况1.nums[i]孤身一人,即dp[i] = nums[i]
情况2.nums[i]前面有人,即dp[i] = dp[i-1] + nums[i]
- 代码
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
int ret = dp[0];
for (int i = 1; i < n; i++) {
dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
ret = Math.max(ret, dp[i]);
}
return ret;
}
- 分治算法
将数组分为左数组和右数组后,拥有最大和的连续子数组的出现位置有3中情况
情况1.子数组在左数组中
清理2.子数组在右数组中
情况3.子数组跨越左右两个数组
- 代码
public int getMax(int[] nums, int low, int high) {
// 如果数组只有一个元素
if (low == high) {
return nums[low];
}
// 将数组分为左数组和右数组
int mid = low + (high - low) / 2;
// 求左数组的连续子数组的最大和
int leftMax = getMax(nums, low, mid);
// 求右数组的连续子数组的最大和
int rightMax = getMax(nums, mid + 1, high);
// 求跨越跨越左右两个数组的连续子数组的最大和
int crossMax = getCrossMax(nums, low, mid, high);
// 三者取最大
return Math.max(Math.max(leftMax, rightMax), crossMax);
}
// 子数组跨越左右两个数组的情况下的最大和
public int getCrossMax(int[] nums, int low, int mid, int high) {
// 既然是跨越两个数组,则左数组的最右元素
// 和右数组的最左元素必然在拥有最大和连续子数组中
// 左数组从最右向左的累加和
int leftSum = nums[mid];
// 左数组从最右向左的子数组的最大和
int leftMax = nums[mid];
// 左数组从最右向左的累加和
for (int i = mid - 1; i >= low; i--) {
// 累加
leftSum += nums[i];
// 记录最大
leftMax = Math.max(leftMax, leftSum);
}
// 右数组同理
int rightSum = nums[mid+1];
int rightMax = nums[mid+1];
for (int i = mid + 2; i <= high; i++) {
rightSum += nums[i];
rightMax = Math.max(rightMax, rightSum);
}
return leftMax + rightMax;
}
public int maxSubArray(int[] nums) {
return getMax(nums, 0 , nums.length - 1);
}