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

题目

给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的。数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],…arr[n-1],arr[0],…,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选)。

输入:

输入包含多个测试用例,每个测试用例共有两行,第一行是一个整数n(1<=n<= 100000),表示数组的长度,第二行依次输入n个整数(整数绝对值不大于1000)。

输出:

对于每个测试用例,请输出子数组和的最大值。

样例输入:

6

1 -2 3 5 -1 2

5

6 -1 5 4 -7

样例输出:

10

14

思路一

[LeetCode]53.Maximum Subarray题目相类似,唯一区别是本题是首尾相连,首尾相连的数组难点是到达尾部后继续从头开始,比类似题目稍微复杂些。

这里采用拉长数组的方法避免了这些问题:将数组平铺为一个长度为2倍原先长度的的新数组,这样问题就变成了:求一个整型数组中长度不超过len(原数组长度)的子数组和的最大值,降低了难度。

代码

       /*---------------------------------------------
    *   日期:2015-02-20
    *   作者:SJF0115
    *   题目: 求首尾相连数组的最大子数组和
    *   来源:淘宝
    *   博客:
    -----------------------------------------------*/
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;

    class Solution {
    public:
        int MaxSubarray(int a[],int n){
            if(n <= 0){
                return 0;
            }//if
            int size = 2*n;
            // 构造2倍长度数组
            vector<int> num(a,a+n);
            for(int i = 0;i < n;++i){
                num.push_back(a[i]);
            }//for
            int max = 0;
            int sum = 0,start = 0,end = 0;
            for(int i = 0;i < size;++i){
                sum += num[i];
                if(sum < 0){
                    sum = 0;
                    start = i+1;
                }//if
                if(start >= n || (i - start + 1) > n){
                    break;
                }//if
                if(max < sum){
                    max = sum;
                    end = i;
                }//if
            }//for
            cout<<"最大数组["<<start%n<<","<<end<<"]"<<endl;
            return max;
        }
    };

    int main() {
        Solution solution;
        int num[] = {-1,-5,-4,-7};
        int result = solution.MaxSubarray(num,4);
        cout<<result<<endl;
    }

思路二

可以把问题的解分为两种情况:

(1)解没有跨过A[n-1]到A[0]

(2)解跨过A[n-1]到A[0]

对于这种情况,只要找到从A[0]开始和最大的一段(A[0]…..A[j])(0 <= j < n)

以及以A[n-1]结尾的和最大的一段(A[i]…..A[n-1])(0 <= i < n)

该种情况的最大值为A[i]+…..+A[n-1]+A[0]+….+A[j]

如果i <= j 则最大值为A[0]+…..+A[n-1]否则最大值为A[i]+…..+A[n-1]+A[0]+….+A[j]

最后,取两种情况的最大值就可以了。求解跨过A[n-1]到A[0]的情况只需要遍历数组一次,故总的时间复杂度为O(N)+O(N) = O(N)

代码

    /*---------------------------------------------
    *   日期:2015-02-20
    *   作者:SJF0115
    *   题目: 求首尾相连数组的最大子数组和
    *   来源:淘宝
    *   博客:
    -----------------------------------------------*/
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;

    class Solution {
    public:
        int MaxSubarray(int a[],int n){
            if(n <= 0){
                return 0;
            }//if
            int max = 0;
            int sum = 0,start = 0;
            // 第一种情况
            for(int i = 0;i < n;++i){
                sum += a[i];
                if(sum < 0){
                    sum = 0;
                    start = i+1;
                }//if
                if((i - start + 1) > n){
                    break;
                }//if
                if(max < sum){
                    max = sum;
                }//if
            }//for
            // 第二种情况
            int sumLeft = 0,sumRight = 0;
            int maxLeft = 0,maxRight = 0;
            int left = 0,right = n-1;
            // 以a[0]开头的最大连续和
            for(int i = 0;i < n;i++){
                sumLeft += a[i];
                if(sumLeft < 0){
                    break;
                }//if
                if(maxLeft < sumLeft){
                    maxLeft = sumLeft;
                    left = i;
                }//if
            }//for
            // 以a[n-1]结尾的最大连续和
            for(int j = n-1;j >= 0;--j){
                sumRight += a[j];
                if(sumRight < 0){
                    break;
                }//if
                if(maxRight < sumRight){
                    maxRight = sumRight;
                    right = j;
                }//if
            }//for
            if(left >= right){
                return max;
            }//if
            return max > (maxLeft + maxRight)?max:(maxLeft+maxRight);
        }
    };

    int main() {
        Solution solution;
        //int num[] = {1,-2,3,5,-1,2};
        //int num[] = {6,-1,5,4,-7};
        int num[] = {-1,-3,-4};
        int result = solution.MaxSubarray(num,3);
        cout<<result<<endl;
    }
时间: 2024-10-24 00:14:05

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

结对编程之求首尾相连数组中最大子数组的和

1.题目: 返回一个整数数组中最大子数组的和. 2.要求: 输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.如果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大.同时返回最大子数组的位置.求所有子数组的和的最大值.要求时间复杂度为O(n). 3.设计思想: 分情况讨论最大子数组可能出现的情况,第一种为正常情况,没有超过数组范围,第二种则比较复杂,要用到环的一部分元素,分而求出两

NYOJ 745 首尾相连数组的最大子数组和

首尾相连数组的最大子数组和 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的.数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],…arr[n-1],arr[0],…,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选). 输入 输入包含多个

结对开发(求二维首尾相接数组的最大子数组和)

一.题目要求 输入一个二维整形数组,数组里有正数也有负数. 二维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值. 要求时间复杂度为O(n)题目:返回一个二维整数数组中最大子数组的和 一.设计思想 求环形二维数组最大子数组的和,可以转化为求一维数组最大子数组的和 我们有一个最初的二维数组a[n][n]找它的 最大子数组之和 1.我们先建立一个新的二维数组b[n][2*n-1], 2,这个新的二维数组就是将初始的二

结对(求数组的最大子数组和)

题目: 返回一个整数数组中最大子数组的和. 要求: 输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 如果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大. 同时返回最大子数组的位置. 求所有子数组的和的最大值. (我主要负责程序分析,代码编程:张金负责代码复审,代码测试计划.) 思路: 与第一次的不同之处,只在于首尾相连,构成了一个环.思路差不多,我们构造了三个数组:(A)

求一个二维数组的最大子数组

小组成员:周其范  胡宝月 上课的时候老师布置的题目是求一个二维数组的最大子数组,因为以前的时候老师要求我们做过一个题目就是求一个数组的最大子数组,当时的方法就是利用循环把所有可能算出,然后比较那个最大就是那个,也就是所说的枚举法.因此这次我们同样的想到了枚举法.但当我们讨论的时候发现了二维有些麻烦,所以我俩在想有没有什么别的方法,最后我们想到了其实二维数组和一位数组有相似之处,可以先把二维数组变成一维数组在算. 对于imin和imax之间的的每一列,都相当于一个一维的元素,假设数组是BC,那么

首尾相连的二维数组的最大子数组

一.设计思路:通过综合求二维数组的最大子数组.求首尾相连的一维数组的最大子数组的算法,得出如下思路:首先将二维数组的子数组上下相加转化成许多一维数组,然后按照求首尾相连的一维数组的算法,遍历一维数组的所有子数组,求出子数组的最大值,即为首尾相连二维数组的子数组的最大值,并且在遍历过程中保留取得最大值的位置,输出二维数组的最大子矩阵. 二.代码: import java.awt.Point; import java.util.Scanner; public class main { public

Task 4.3 求环形数组的最大子数组和

任务要求:输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 如果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大.同时返回最大子数组的位置. 求所有子数组的和的最大值.要求时间复杂度为O(n) 1.设计思想:(假设数组长度为n.)任务要求中提出了数组可以首尾相邻,这样在求数组最大子数组和的时候就要考虑两种情况:一是最大子数组和所在数组在A[0]...A[n]之间,不包括首尾相

nyoj 983 ——首尾相连数组的最大子数组和——————【最大子串和变形】

首尾相连数组的最大子数组和 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的.数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],…arr[n-1],arr[0],…,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选). 输入 输入包含多个

NYOJ 983 首尾相连数组的最大子数组和

首尾相连数组的最大子数组和 时间限制:1000 ms  |  内存限制:65535 KB 描述 给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的.数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],-arr[n-1],arr[0],-,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选). 输入 输入包含多个测试用例,