zoukankan      html  css  js  c++  java
  • 最大子数组问题全解

    问题描述

    给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。

    问题解析

    很经典的一个问题,下面给出3种解法,暴力解法、分治算法、动态规划。这个题Leetcode上有大量测试数据,只不过最后两个测试数据要求算法复杂度为n,只能用动态规划来解,可以借鉴一下,链接见这里https://leetcode.com/problems/maximum-subarray/description/

    问题解决

    1、暴力解法

    穷举所有的子串,计算他们的和,然后从中找出最大的一个。

    //最大子数组的暴力解法
    int maxSubArray1(vector<int>& nums) {
        int max = INT_MIN;
        for (int i = 0; i < nums.size(); ++i) {
            for (int j = i; j < nums.size(); ++j) {
                int temp = 0;
                for (int k = i; k < j; ++k) {
                    temp += nums[k];
                }
                if (temp > max)
                    max = temp;
            }
        }
        return max;
    }

    2、分治算法

    首先,将数组从中间分为两个部分

    在此基础上我们考虑最大子串的情况,最大最子串的位置可能有两种:

    第一种,只在Part1或是Part2之中,不跨越中间线。这种情况直接采用递归求出

    第二种,跨越中间线。这种情况要寻找最大子串,我们从中间线开始,向左右两侧拓展,分别找到左侧最大值和右侧最大值,然后相加。

    例如,所给数组为{ -2,1,-3,4,-1,2,1,-5,4 },中间位置为-1处,要求跨越中间线的最大子串,我们从-1开始向左遍历,得到子串{4,-1}、{-3,4,-1}、{1,-3,4,-1}和{-2,1,-3,4,-1}找出左侧最大子串{4,-1}。然后向右遍历,依次得到{-1,2}、{-1,2,1}、{-1,2,1,-5}、{-1,2,1,-5,4},其中右侧最大子串为{-1,2,1},最后将左侧最大子串和右侧最大子串相加即可。

    //最大子数组的分治解法
    int maxstr(vector<int>& nums,int left,int right) {
        //递归停止条件
        if (left == right)
            return nums[left];
        int mid = (left + right) / 2;
        //左侧递归
        int leftmax = maxstr(nums,left,mid);
        //右侧递归
        int rightmax = maxstr(nums,mid + 1, right);
        //从中间线向左寻找
        int lmax INT_MIN;
        int l = 0;
        for (int i = mid; i >= 0; --i) {
            l += nums[i];
            if (l > lmax)
                lmax = l;
        }
        //从中间线向右寻找
        int rmax = INT_MIN;
        int r = 0;
        for (int i = mid; i <= right; ++i) {
            r += nums[i];
            if (r > rmax)
                rmax = r;
        }
        int midmax = lmax + rmax -nums[mid];
        return  leftmax > rightmax?max(leftmax,midmax):max(rightmax,midmax);
    }
    int maxSubArray2(vector<int>& nums) {
        return maxstr(nums,0,nums.size()-1);
    }

    3、动态规划

    这也是效率最高的一种办法,只需要遍历一遍,但思路有些难理解。

    假设一个串a>0,那么这个串加上另一个串b一定比b要大,按照这个思路,从第一个数开始累加,如果累加之和小于0,则弃掉之前的数,从数组之后的位置重新开始累加,知道数组遍历完成,找出其中最大的数。(由于被弃掉时一定是遇到了一个绝对值大于前面所有正数的负数串,所以最大子串一定不能包含该负数串,因为在加上该负数串之前的串一定更大)

    //最大子数组的动态规划解法
    int maxSubArray3(vector<int>& nums) {
        int max = INT_MIN;
        int sum = 0;
        for (int i = 0; i < nums.size(); ++i) {
            sum += nums[i];
            if (sum > max)
                max = sum;
            if (sum < 0)
                sum = 0;
        }
        return max;
    }
  • 相关阅读:
    phpinfo mac 和 php -moudle里的不一致(mongodb篇)
    0、服务启动前之日志字段和格式
    P3740 贴海报
    树状数组区间修改and查询和
    P1823 Patrik 音乐会的等待
    西安段素扫描线
    P1903 数颜色
    P1220 关路灯
    [p1559] 运动员最佳匹配问题
    treap数组版
  • 原文地址:https://www.cnblogs.com/likaiming/p/8570205.html
Copyright © 2011-2022 走看看