• 数组中最大和的子数组


    题目:

    输入一个整型数组,数据元素有正数也有负数,求元素组合成连续子数组之和最大的子数组,要求时间复杂度为O(n)

    例如:

    输入的数组为1, -2, 3, 10, -4, 7, 2, -5,最大和的连续子数组为3, 10, -4, 7, 2,其最大和为18

    背景:

    本题最初为2005年浙江大学计算机系考研题的最后一道程序设计题,在2006年里包括google在内的很多知名公司都把本题当作面试题。

    由于本题在网络中广为流传,本题也顺利成为2006年程序员面试题中经典中的经典。

     

    分析:

    如果不考虑时间复杂度,我们可以枚举出所有子数组并求出他们的和。不过非常遗憾的是,由于长度为n的数组有O(n2)个子数组(即:n + n-1 + ... + 1=n(n+1)/2);而且求一个长度为n的数组的和的时间复杂度为O(n)。因此这种思路的时间是O(n3)

    很容易理解,当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。基于这样的思路,我们可以写出如下代码。

    1. void MaxSum(int array[], unsigned int len)  
    2. {  
    3.     if(NULL == array || len <=0){  
    4.         return;  
    5.     }  
    6.   
    7.     int curSum = 0, maxSum = 0;  
    8.     int i = 0;  
    9.     for(i=0; i<len; i++){  
    10.         curSum += array[i];     // 累加  
    11.   
    12.         if(curSum < 0){          // 当前和小于0,重置为0  
    13.             curSum = 0;  
    14.         }  
    15.   
    16.         if(curSum > maxSum){ // 当前和大于最大和,则重置最大和  
    17.             maxSum = curSum;   
    18.         }  
    19.     }  
    20.   
    21.     if(maxSum == 0){            // 最大和依然为0,说明数组中所有元素都为负值  
    22.         maxSum = array[0];  
    23.         for(i=1; i<len; i++){  
    24.             if(array[i] > maxSum){  
    25.                 maxSum = array[i];  
    26.             }  
    27.         }  
    28.     }  
    29.   
    30.     printf("maxSum: %d", maxSum);  
    31. }  

    测试数组:

    1. int array[] = {1, -2, 3, 10, -4, 7, 2, -5};     // 3, 10, -4, 7, 2 = 18  

    运行结果:

    代码改进:

    有时,需要输出最大和的子数组及其开始、结束下标,代码如下:

    1. void MaxSum(int array[], unsigned int len)  
    2. {  
    3.     if(NULL == array || len <=0){  
    4.         return;  
    5.     }  
    6.   
    7.     int curSum = 0, maxSum = 0;  
    8.     int index_start = 0, index_end = 0;     // 初始化子数组最大和下标  
    9.     int i = 0;  
    10.     for(i=0; i<len; i++){  
    11.         curSum += array[i];     // 累加  
    12.   
    13.         if(curSum < 0){          // 当前和小于0,重置为0  
    14.             curSum = 0;  
    15.             index_start = i+1;      // 调整子数组最大和的开始下标  
    16.         }  
    17.   
    18.         if(curSum > maxSum){     // 当前和大于最大和,则重置最大和  
    19.             maxSum = curSum;   
    20.             index_end = i;          // 调整子数组最大和的结束下标  
    21.         }  
    22.     }  
    23.   
    24.     if(maxSum == 0){            // 最大和依然为0,说明数组中所有元素都为负值  
    25.         maxSum = array[0];  
    26.         index_start = index_end = 0;                // 初始化子数组最大和下标  
    27.         for(i=1; i<len; i++){  
    28.             if(array[i] > maxSum){  
    29.                 maxSum = array[i];  
    30.                 index_start = index_end = i;        // 调整子数组最大和下标  
    31.             }  
    32.         }  
    33.     }  
    34.   
    35.     // 输出最大和的子数组及其开始、结束下标  
    36.     printf("index_start: %d index_end: %d ", index_start, index_end);  
    37.     for(i=index_start; i<=index_end; i++){  
    38.         printf("%d ", array[i]);  
    39.     }  
    40.   
    41.     printf(" maxSum: %d", maxSum);  
    42. }  

    测试数组:

    1. int array[] = {1, -2, 3, 10, -4, 7, 2, -5};     // 3, 10, -4, 7, 2 = 18  

    运行结果:

  • 相关阅读:
    Find the Smallest K Elements in an Array
    Count of Smaller Number
    Number of Inversion Couple
    Delete False Elements
    Sort Array
    Tree Diameter
    Segment Tree Implementation
    Java Programming Mock Tests
    zz Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
    Algorithm about SubArrays & SubStrings
  • 原文地址:https://www.cnblogs.com/winscoder/p/3373241.html
Copyright © 2020-2023  润新知