【2】53.最大子序和

53.最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6

解法一:遍历数组
这里的主要思想是如果某段的所有数总和为负数,那么对总结果的最终影响一定是减少的,因此如果出现和为负数,则将其抛弃,总和记为0,再从下一个数开始。

时间复杂度:因为随时更新,因此为O(n)

class Solution
{
public:
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        int sum = 0;
        int Max = nums[0];
        int i, j;
        for (i = 0; i < n; i = j+1) {
            for (j = i; j < n; ++j) {
                sum += nums[j];
                if (sum > Max)
                    Max = sum;
                if (sum < 0) {         //如果和为负数,则将前面的全部抛弃
                    sum = 0;
                    break;
                }
            }
        }
        return Max;
    }
};

解法二:动态规划

其实和解法一大同小异,同样是随时更新sum和Max,还不如解法一好理解
思路:
f(i) = a[i], i <0或f(i-1) <= 0;
f(i) = f(i-1) + a[i], i!=0, f(i-1) > 0
求max(f[i])

class Solution
{
public:
    int maxSubArray(vector<int>& nums)
    {
        int n = nums.size();
        int sum = 0;
        int Max = nums[0];
        for(int i=0;i<n;++i)
        {
            sum=max(sum+nums[i],nums[i]);
            Max=max(Max,sum);
        }
        return Max;
    }
};

解法三:分治法:
这个稍微有点复杂,而且时间复杂度也更高,为O(nlogn)
但是对理解分治算法很有帮助
连续最大子序和分为三种情况:
一是子序列都在左半侧,
二是子序列都在右半侧,
三是子序列跨越中心点分布在左右两边。
因此我们采用递归的方式解题。

class Solution
{
public:
	//找跨中点的最大子数组,我们只需找出形如A[i.. mid] 和A[mid+ 1. .j] 的最大子数组,然后将其合并即可。
    int findMaxCrossingSubArray(vector<int>& a, int left, int mid, int right)
    {
        int left_sum,sum,right_sum;
        sum = 0;
        left_sum = a[mid];
        for(int i = mid; i>=left; i--)//从中间往左边遍历
        {
            sum += a[i];
            if(sum>left_sum) left_sum = sum;
        }
       
        sum = 0;
        right_sum = a[mid+1];
        for(int j = mid+1; j<=right; j++) //从中间往右边遍历
        {
            sum += a[j];
            if(sum>right_sum) right_sum = sum;
        }
        return (left_sum+right_sum);
       
    }

int findMaxSubArray(vector<int>& a, int left, int right)
    {
        if(right == left) return a[left];
       
        int mid = (left+right)/2;
        int left_sum = findMaxSubArray(a, left, mid);
        int right_sum = findMaxSubArray(a, mid+1, right);
        int cross_sum = findMaxCrossingSubArray(a, left, mid, right);
        return max(max(left_sum, right_sum), cross_sum);
       
    }

    int maxSubArray(vector<int>& nums)
    {
        return findMaxSubArray(nums, 0, nums.size()-1);  //递归入口
    }
   
    
};
发布了6 篇原创文章 · 获赞 2 · 访问量 119

猜你喜欢

转载自blog.csdn.net/weixin_43934036/article/details/104253105