最大子数组问题全解

问题描述

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

问题解析

很经典的一个问题,下面给出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;
}

原文地址:https://www.cnblogs.com/likaiming/p/8570205.html

时间: 2024-10-03 09:59:56

最大子数组问题全解的相关文章

jQuery数组处理全解

jQuery的数组处理.便捷.功能齐全.最近的项目中用到的比较多,深感实用,一步到位的封装了很多原生JavaScript数组不能企及的功能.最近时间紧迫,今天抽了些时间回过头来看jQuery中文文档中对数组的介绍,顺便对jQuery数组做个总结,温故而知新. 强烈建议你打开DEMO演示后再看下面的详解:http://mrthink.net/demo/ijq20101125.htm 1. $.each(array, [callback]) 遍历[常用] 解释: 不同于例遍jQuery对象的$().

动态规划法解最大子数组问题

分治法https://www.cnblogs.com/zuofaqi/p/9678356.html 引入了最大子数组问题,它有一个更高效的解决方法就是动态规划法 如果已经直到 A[0...i] 的最大子数组,那么 A[0...i+1] 的最大子数组要么是 A[0...i] 的最大子数组,要么是某个子数组 A[j...i+1] (0<= j <= i+1) 动态规划三要素: 1. 边界:当数组中只有一个元素的时候,最大子数组就是自身 2. 最优子结构:A[0...i+1] 的最优子结构是 A[0

一维数组头尾相连求最大子数组

题目: 返回一个整数数组中最大子数组的和. 要求: 输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.如果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大. 同时返回最大子数组的位置. 求所有子数组的和的最大值.要求时间复杂度为O(n). 1. 设计思想: 因为已经写过了一维数组的求最大子数组程序.所以只是在原程序上进行修改.首先产生随机数数组,然后进行计算,因为要求时间复杂度

最大子数组和(最大子段和)

比如对于数组[1,-2,3,5,-1,2] 最大子数组和是sum[3,5,-1,2] = 9, 我们要求函数输出子数组和的最大值,并且返回子数组的左右边界(下面函数的left和right参数). 本文我们规定当数组中所有数都小于0时,返回数组中最大的数(也可以规定返回0,只要让以下代码中maxsum初始化为0即可,此时我们要注意-1 0 0 0 -2这种情形,特别是如果要求输出子数组的起始位置时,如果是面试就要和面试官问清楚) 以下代码我们在PAT 1007. Maximum Subsequen

最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和

参考:http://www.ahathinking.com/archives/124.html 最长公共子序列 1.动态规划解决过程 1)描述一个最长公共子序列 如果序列比较短,可以采用蛮力法枚举出X的所有子序列,然后检查是否是Y的子序列,并记录所发现的最长子序列.如果序列比较长,这种方法需要指数级时间,不切实际. LCS的最优子结构定理:设X={x1,x2,……,xm}和Y={y1,y2,……,yn}为两个序列,并设Z={z1.z2.……,zk}为X和Y的任意一个LCS,则: (1)如果xm=

归并排序、最大子数组

1.归并排序 分治模式: (1)分解原问题为若干子问题,这些子问题是原问题的规模较小的实例. (2)解决子问题,递归求解子问题.子问题规模足够小时,直接求解. (3)合并子问题的解,得到原问题的解. 归并排序完全遵循分治模式. (1)分解待排序的n个元素列成各具n/2个元素的两个子序列. (2)使用归并排序递归地排序两个子序列. (3)合并两个已排序的子序列,产生已排序的答案. 时间复杂度:T(n)=O(n*lgn) 代码: #include<iostream> #include<vec

分治策略 &nbsp; 最大子数组问题

递归式 递归式与分治方法是紧密相关的,因为使用递归式可以很自然地刻画分治算法的运行时间.一个递归式就是一个等式或不等式,它通过更小的输入上的函数值来描述一个函数.例如,在2.3.2节,我们用递归式描述了MERGE-SORT过程的最坏情况运行时间T(n): Θ(1)        若n=1 T(n) =                         (4.1) 2T(n/2)+Θ(n)    若n>1 求解可得T(n)=Θ(nlgn) 递归式可以有很多形式.例如,一个递归算法可能将问题划分为规模

[经典面试题][淘宝]求首尾相连数组的最大子数组和

题目 给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的.数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],-arr[n-1],arr[0],-,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选). 输入: 输入包含多个测试用例,每个测试用例共有两行,第一行是一个整数n(1<=n<= 100000),表示数组的长度

phpEXCEL操作全解

phpExcel中文帮助手册,列举了各种属性,以及常用的操作方法,难得是每一个都用实例加以说明,希望对大家有所帮助. phpExcel中文帮助手册,不可多得的好文章,供大家学习参考. 1.设置excel的属性: 创建人 $objPHPExcel->getProperties()->setCreator("Maarten Balliauw"); 最后修改人 $objPHPExcel->getProperties()->setLastModifiedBy("