剑指offer:连续子数组的最大和

问题:求连续子数组的最大和

算法1:

首先用一个变量maxSum来保存最大和。

从数组的第一元素开始,遍历整个数组。并用currSum来保存遍历过程中最大子数组的和。

在遍历每个元素的时候:

1、首先,将这个元素和最大和maxSum比较,如果大于maxSum,就将这个元素赋给maxSum。

2、同时,判断当前子数组的和currSum是否大于0。如果currSum大于0,将这个元素的值和currSum相加。否则,将当前元素的值直接赋给currSum。(为什么?我是这么考虑的,如果遍历到第i个元素,第i个元素之前的子数组的和currSum,且currSum的值为负,那么如果currSum和第一个元素相加,不论第i个元素为什么,最终的和与第i个元素相比较,只会更小。所以说,如果currSum为负,currSum只会使削弱后面子数组的和,所以舍弃这个负的值)

3、比较currSum和maxSum,如果maxSum小于currSum,就把currSum赋值给maxSum

代码如下:

class Solution {

public:

//求解问题代码开始

    int FindGreatestSumOfSubArray(vector<int> array) {
        //
        if (array.size() == 0){
            //throw new exception();
            return 0;
        }
        
        int maxSum = 0x80000000;
        int currSum = 0x80000000;
        for (vector<int>::iterator ite = array.begin(); ite != array.end(); ite++){
            
            if (*ite > maxSum){
                maxSum = *ite;
            }
            if (currSum < 0){
                currSum = *ite;
            }
            else {
                currSum += *ite;
            }
            if (currSum > maxSum){
                maxSum = currSum;
            }
        }
    
        return maxSum;
    }

};


上面算法的优点是,多项式时间内即可完成比较。缺点是,没有给出哪段元素的和最大。

当然,也可采用分治算法求解这道题目。


算法2:采用分治法:

1、将一个数组分为两部分,左半部分和有半部分;分别求这两部分的最大子数组的和(递归)。

2、整个数组的最大子数组和也可能是跨越这两部分数组,因此还得求跨越左右两部分子数组的最大子数组和

3、最后比较这三部分,并返回最大值。


class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        //
        if (array.size() == 0){
            //throw new exception();
            return 0;
        }
        
        int maxSum = 0x80000000;
        maxSum = FindGreatSumOfSubArray(array, 0, array.size() - 1);
    
        return maxSum;
    }
    int FindGreatSumOfSubArray(vector<int> &array, int begin, int end){
        if (begin == end){
            return array[begin];
        }
        int max = 0;
        int mid = (begin + end) / 2;.//使用mid将数组分为两部分
        int leftMax = FindGreatSumOfSubArray(array, begin, mid);//求左半部分最大和
        int rightMax = FindGreatSumOfSubArray(array, mid + 1, end);//求有半部分最大和
        //接下来求跨越左半部分和有半部分的最大和
        int midtoLeftMax = 0x80000000;
        int midtoRightMax = 0x80000000;
        int midMax;
        
        for (int i = mid, currSum = 0; i >= begin; i--){
            currSum += array[i];
            if (currSum > midtoLeftMax){
                midtoLeftMax = currSum;
            }
        }
        for (int i = mid + 1, currSum = 0; i <= end; i++){
            currSum += array[i];
            if (currSum > midtoRightMax){
                midtoRightMax = currSum;
            }
        }
        
        if (midtoLeftMax >= 0 && midtoRightMax >= 0){
            midMax = midtoLeftMax + midtoRightMax;
        }
        else {
            midMax = midtoLeftMax > midtoRightMax ? midtoLeftMax : midtoRightMax;
        }
        //返回左半部分最大和、有半部分最大和、跨越左半部分和右半部分最大和中最大的一个
        max = leftMax > rightMax ? leftMax : rightMax;
        max = max > midMax ? max : midMax;
        return max;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值