53.最大子数组和
暴力解法1:枚举左右端点在对区间内的值求和
class Solution {
public:int maxSubArray(vector<int>& nums) {// 暴力解 O(n^3)=枚举左端点+枚举右端点+求左端点到右端点的和sum// 但对左端点到右端点求和,这一步可以简化为O(1),从而整体复杂度达到O(n^2)// 因为在确定了左端点的前提下,枚举右端点,sum每次加一个右端点元素即可int maxSum = -10e6;int start = 0, end = 0;for (int left = 0; left < nums.size(); left++) {int temp = 0;for (int right = left; right < nums.size(); right++) {temp += nums[right];if (maxSum < temp) {maxSum = temp;start = left;end = right;}}}return maxSum;}
};
动态规划解法2:f[i]表示以i为结尾,0~i子数组的最大子数组和
f[i]状态转移方程:if(f[i-1]<0)f[i]=nums[i];else f[i]=f[i-1]+nums[i];
class Solution {
public:int maxSubArray(vector<int>& nums) {vector<int> f(nums.size());f[0]=nums[0];int max=nums[0];for(int i=1;i<nums.size();i++){if(f[i-1]<0)f[i]=nums[i];else{f[i]=f[i-1]+nums[i];}if(max<f[i])max=f[i];}return max;}
};
武大真题要在求出最大子数组和的基础上,输出最大子数组的下标
思路:递归求解f[i]并将f[i]与maxSum进行比较 如果f[i]大于maxSum则更新leftIndex,rightIndex。此时的最大子数组的右端点rightIndex必然是i,左端点leftIndex是tempStart。
tempStart记录着当前以i为结尾的最大子数组和的左端点。
#include<iostream>
#include<vector>
using namespace std;
int main() {vector<int> nums= {-10,-7,-8};int maxSum=nums[0];int leftIndex=0,rightIndex=0;vector<int> f(nums.size(),0);//f[i]表示以i为结尾的子数组的最大子数组和。因为f[]必然包含题解f[0]=nums[0];int tempStart=0; //for(int i=1; i<nums.size(); i++) {if(f[i-1]>=0) {f[i]=f[i-1]+nums[i];} else {f[i]=nums[i];tempStart=i;}if(f[i]>maxSum){rightIndex=i;leftIndex=tempStart;maxSum=f[i];}}printf("最大子数组和为: %d。左端点: %d右端点: %d",maxSum,leftIndex+1,rightIndex+1);return 0;
}