53.最大子数组和及武大机试真题

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;
}
posted @ 2025-03-25 22:45  Cheauncey  阅读(28)  评论(0)    收藏  举报