zoukankan      html  css  js  c++  java
  • 最大子串和问题(Maximum Subarray)

     此文章为http://blog.csdn.net/joylnwang/article/details/6859677的博客

    最大子串和问题(Maximum Subarray)

    又一个经典问题,对于一个包含负值的数字串array[1...n],要找到他的一个子串array[i...j](0<=i<=j<=n),使得在array的所有子串中,array[i...j]的和最大。

    这里我们需要注意子串和子序列之间的区别。子串是指数组中连续的若干个元素,而子序列只要求各元素的顺序与其在数组中一致,而没有连续的要求。对于一个元素数为n的数组,其含有2^n个子序列和n(n+1)/2个子串。如果使用穷举法,则至少需要O(n^2)的时间才能得到答案。卡耐基梅隆大学的Jay Kadane的给出了一个线性时间算法,我们就来看看,如何在线性时间内解决最大子串和问题。

    要说明Kadane算法的正确性,需要两个结论。首先,对于array[1...n],如果array[i...j]就是满足和最大的子串,那么对于任何k(i<=k<=j),我们有array[i...k]的和大于0。因为如果存在k使得array[i...k]的和小于0,那么我们就有array[k+1...j]的和大于array[i...j],这与我们假设的array[i...j]就是array中和最大子串矛盾。

    其次,我们可以将数组从左到右分割为若干子串,使得除了最后一个子串之外,其余子串的各元素之和小于0,且对于所有子串array[i...j]和任意k(i<=k<j),有array[i...k]的和大于0。此时我们要说明的是,满足条件的和最大子串,只能是上述某个子串的前缀,而不可能跨越多个子串。我们假设array[p...q],是array的和最大子串,且array[p...q],跨越了array[i...j],array[j+1...k]。根据我们的分组方式,存在i<=m<j使得array[i...m]的和是array[i...j]中的最大值,存在j+1<=n<k使得array[j+1...n]的和是array[j+1...k]的最大值。由于array[m+1...j]使得array[i...j]的和小于0。此时我们可以比较array[i...m]和array[j+1...n],如果array[i...m]的和大于array[j+1...n]则array[i...m]>array[p...q],否array[j+1...n]>array[p...q],无论谁大,我们都可以找到比array[p...q]和更大的子串,这与我们的假设矛盾,所以满足条件的array[p...q]不可能跨越两个子串。对于跨越更多子串的情况,由于各子串的和均为负值,所以同样可以证明存在和更大的非跨越子串的存在。对于单元素和最大的特例,该结论也适用。

    根据上述结论,我们就得到了Kadane算法的执行流程,从头到尾遍历目标数组,将数组分割为满足上述条件的子串,同时得到各子串的最大前缀和,然后比较各子串的最大前缀和,得到最终答案。我们以array={−2, 1, −3, 4, −1, 2, 1, −5, 4}为例,来简单说明一下算法步骤。通过遍历,可以将数组分割为如下3个子串(-2),(1,-3),(4,-1,2,1,-5,4),这里对于(-2)这样的情况,单独分为一组。各子串的最大前缀和为-2,1,6,所以目标串的最大子串和为6。

    下面是实现代码:

    [cpp] view plaincopy
     
    1. int Kadane(const int array[], size_t length, unsigned int& left, unsigned int& right)  
    2. {  
    3.     unsigned int i, cur_left, cur_right;  
    4.     int cur_max, max;  
    5.   
    6.     cur_max = max = left = right = cur_left = cur_right = 0;  
    7.   
    8.     for(i = 0; i < length; ++i)  
    9.     {  
    10.         cur_max += array[i];  
    11.   
    12.         if(cur_max > 0)  
    13.         {  
    14.             cur_right = i;  
    15.   
    16.             if(max < cur_max)  
    17.             {  
    18.                 max = cur_max;  
    19.                 left = cur_left;  
    20.                 right = cur_right;  
    21.             }  
    22.         }  
    23.         else  
    24.         {  
    25.             cur_max = 0;  
    26.             cur_left = cur_right = i + 1;  
    27.         }  
    28.     }  
    29.   
    30.     return max;  
    31. }  

    这里我们需要注意,对于数组元素全为负的情况,由于不满足上述的两条结论,所以Kadane算法无法给出正确答案。

    该问题是1977年Ulf Grenander提出的一个数字图像方面的问题,1984年Jay Kadane才给出了这个优美的解决方案。有些问题,看似解法简单,但是实际上其原理,要比代码复杂得多。

    nyoj  44  字串和

    http://acm.nyist.net/JudgeOnline/problem.php?pid=44

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 using namespace std;
     5 int main()
     6 {
     7     int n;
     8     scanf("%d",&n);
     9     while(n--)
    10     {
    11         int t,sum=0,a,max=0;
    12         scanf("%d",&t);
    13         scanf("%d",&sum);
    14         max=sum;
    15         while(--t)
    16         {
    17             scanf("%d",&a);
    18             if(sum<0)
    19             sum=a;
    20             else
    21             sum+=a;
    22             if(max<sum)
    23             max=sum;
    24         }
    25         printf("%d
    ",max);
    26     }
    27     return 0;
    28 }
  • 相关阅读:
    Redis源码分析(二十一)--- anet网络通信的封装
    leetcode 总结part1
    leetcode String to Integer (atoi)
    leetcode 165. Compare Version Numbers
    leetcode 189. Rotate Array
    leetcode 168. Excel Sheet Column Title
    leetcode 155. Min Stack
    leetcode 228. Summary Ranges
    leetcode 204. Count Primes
    leetcode 6. ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/nylg-haozi/p/3178497.html
Copyright © 2011-2022 走看看