📅  最后修改于: 2023-12-03 15:08:06.540000             🧑  作者: Mango
在处理数组问题时,有时需要找到数组中连续子数组的最大和。这种问题可以使用动态规划来解决。
假设$dp[i]$表示以第$i$个元素结尾的连续子数组的最大和,则有: $$ dp[i] = max(dp[i-1]+nums[i], nums[i]) $$ 其中$nums$是原始数组。从$dp[0]$开始往后进行迭代,每次更新$dp[i]$即可得到最终的答案。
以下是动态规划的C++实现代码:
int maxSubArray(vector<int>& nums) {
if(nums.empty()) return 0;
vector<int> dp(nums.size());
dp[0] = nums[0];
int ans = dp[0];
for(int i=1; i<nums.size(); i++) {
dp[i] = max(dp[i-1]+nums[i], nums[i]);
ans = max(ans, dp[i]);
}
return ans;
}
还有一种更快速的求解方式——分治法。
将数组$nums$从中间分为左右两个子数组,那么最大子数组要么在左半部分,要么在右半部分,要么跨度中间。
递归求解左右两半的最大子数组,然后求跨越中间的最大子数组。最终答案就是三者之中的最大值。
以下是分治法的C++实现代码:
int maxSubArray(vector<int>& nums) {
if(nums.empty()) return 0;
return maxSubArrayHelper(nums, 0, nums.size()-1);
}
int maxSubArrayHelper(vector<int>& nums, int left, int right) {
if(left == right) return nums[left];
int mid = (left+right)/2;
int leftSum = maxSubArrayHelper(nums, left, mid);
int rightSum = maxSubArrayHelper(nums, mid+1, right);
int crossSum = findMaxCrossing(nums, left, mid, right);
return max(max(leftSum, rightSum), crossSum);
}
int findMaxCrossing(vector<int>& nums, int left, int mid, int right) {
int leftSum = INT_MIN;
int rightSum = INT_MIN;
int sum = 0;
for(int i=mid; i>=left; i--) {
sum += nums[i];
if(sum > leftSum) leftSum = sum;
}
sum = 0;
for(int i=mid+1; i<=right; i++) {
sum += nums[i];
if(sum > rightSum) rightSum = sum;
}
return leftSum+rightSum;
}
本文介绍了使用动态规划和分治法来解决数组中连续子数组的最大和问题。两种方法各有优缺点,可以根据实际情况选择使用。