剑指offer系列——30.连续子数组的最大和

Q:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
T:
1.对于一个数A,若是A的左边累计数非负,那么加上A能使得值不小于A,认为累计值对整体和是有贡献的。如果前几项累计值负数,则认为有害于总和,total记录当前值。
注意:C++中表示正无穷是INF_MAX,负无穷是INF_MIN,需要 #include

    int FindGreatestSumOfSubArray(vector<int> array) {
        if (array.empty())
            return 0;
        int max = INF_MIN;
        int cur = 0;
        for (int i = 0; i < array.size(); i++) {
            cur += array[i];
            if (cur > max)
                max = cur;
            if (cur < 0)
                cur = 0;
        }
        return max;
    }

2.动态规划法:遍历数组,定义一个变量来存储当前向量子序列最大值,\(F(i)=max(F(i-1)+array[i] , array[i])\)

    int FindGreatestSumOfSubArray(vector<int> array) {
        if (array.empty())
            return 0;
        int result = array[0];
        int cur = array[0];
        for (int i = 1; i < array.size(); i++) {
            cur = max(cur + array[i], array[i]);
            result = max(result, cur);
        }
        return result;
    }

3.分治法:
考虑将数组从中间分为两个子数组,则最大的比出现在三种情况之一

  1. 完全位于左边数组
  2. 完全位于右边数组
  3. 跨越中点,包含左右数组靠近中点的部分

具体实现: 递归左右子数组再分为两个数组,直到子数组只有一个元素

    int FindGreatestSumOfSubArray(vector<int> array) {
        if (array.empty())
            return 0;
        return Find(array, 0, array.size() - 1);
    }

    int Find(vector<int> array, int left, int right) {
        if (left == right) {
            return array[left];
        }
        int mid = (left + right) / 2;
        //跨越中点,包含左右数组靠近中点的部分
        int maxLeftm = INT_MIN;
        int temp = 0;
        for (int i = mid; i >= left; i--) {
            temp = temp + array[i];
            maxLeftm = max(maxLeftm, temp);
        }
        int maxRightm = INT_MIN;
        temp = 0;
        for (int i = mid + 1; i <= right; i++) {
            temp = temp + array[i];
            maxRightm = max(maxRightm, temp);
        }
        int maxMid = maxLeftm + maxRightm;
        //完全位于左边数组
        int maxLeft = Find(array, left, mid);
        //完全位于右边数组
        int maxRight = Find(array, mid + 1, right);
        return max(maxRight, max(maxMid, maxLeft));
    }
posted @ 2020-02-13 20:51  Shaw_喆宇  阅读(150)  评论(0编辑  收藏  举报