求子数组的最大和

声明:题目来自: http://blog.csdn.net/v_JULY_v/archive/2010/11/17/6015165.aspx  JULY整理了100道微软等公司的面试题目,我想先不看答案:http://blog.csdn.net/v_JULY_v/archive/2011/01/10/6126406.aspx 自己先做一遍。

题目:

 

输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。

 

思路:

 

一般情况下,我都是先举一些具体的例子,在纸上比划比划,看看在比划的过程中有没有什么规律可循。首先我想到的还是dynamic programming 的思路,但是我总结不出sub optimal structure来,你说 一个数组A[0..K] 的最大和子数组和 A[0..K-1]有什么关系呢?所以接下来我们看几个例子:

 

情况1: [ -1 -2 -3 4 5 6 -4 -5 ]  这个例子中,显然最大和子数组是 4 5 6, 那我是不是可以下结论说,首先把给定的数组的左边和右边的负数都去掉?我一开始真这么想来着,后来我同事说:“如果整个给定的数组中全是负数呢?”,是呀!我没有考虑到这个:

 

情况2: [ -5 -4 -1 -2 -3 -8 ] 如果全是负数,那最大子数组是 -1, 如果我按照上面的思路,在预处理的时候分别从最左边和最右边把负数都先去掉,那就没有最大和子数组存在了! 教训1:在纸上举例子比划的时候,一定不要忘记边界情况,在这里是 全是正数,或者全是负数!

再看,在全是负数的时候,其实每次我们拿到一个新的数A[k], 我都认为这有可能是一个最大子数组,初始化的时候 maxSum= A[0], 然后迭代整个数组,if(A[k] > maxSum) { maxSum = A[k];  maxBegin = k, maxEnd=k+1} 。 这里,maxBegin 和 maxEnd用来记录 随后的最大子数组,最大子数组的元素为 A[i], maxBegin <= i < maxEnd; maxSum是指到目前位置最大子数组的和。

 

情况3: [ -5 -4 -1 1 2 3 ] 当我们读到 1 的时候, 之前记录的最大的元素位置maxBegin=2,maxEnd=3 最大值是A[maxBegin] = -1, 当前元素位置currentIndex=3, 当前值A[currentIndex] = 1, 于是我们应该更新 maxBegin=currentIndex=3, maxEnd=maxBegin+1 = 4 然后读入下个元素2, 注意,这个时候和情况2不同的是,不是if(A[k] > maxSum), 而是 if(A[k] + currentSum) { maxEnd = k+1; maxSum = A[k]+currentSum; } 这里,currentSum 的值是 1。

 

情况2 和 情况3 的唯一不同是: 在数组的迭代过程中,情况2在每次迭代的时候,都重置currentSum=0, 而情况3在读到元素1以后,就不重置currentSum了。还有,情况2中每读入一个新的元素,它都有可能是最大子数组的开始,但是在情况3中,元素2,3不可能是新的最大子数组的开始位置。--> 似乎我们可以得出规律:“如果上一次读到的元素是负数,我们属于情况2 (RESET状态):我们记录当前位置,并且在和maxSum比较以后,重置currentSum=0; 如果上一次读到的元素是正数,我们属于情况3(EXTEND状态): 我们不记录当前位置,和maxSum比较后不重置currentSum。

 

情况4: [ -5 -4 -1 1 2 3 -2 x y] 情况4 和情况3 在读到-2 之前是一样的,读到-2之前,最大和子数组是[1 2 3], 当前状态是EXTEND, currentSum = maxSum = 6, 我们注意到如果 x >=2, 我们就应该把[1 2 3]扩展到 [1 2 3 -2 x]; 如果 x < 2 , 我们还要看 x+y 是不是 >=2 ? hmm~~这样看似乎还是做不出判断,再仔细看看:

如果 currentSum + (-2) + x < 0 , 则 [1 2 3 -2 x] 一定不能扩展到 [1 2 3 -2 x y] 因为 currentSum = 1+2+3-2+x < 0 ,所以 y + currentSum < y !

如果 currentSum + (-2) + x + y > maxSum, 则 [1 2 3] 一定能扩展到 [ 1 2 3 -2 x y]。

 

所以: 情况4 应该总结成:

if( currentMode == EXTEND && currentSum + A[k] > maxSum) { maxSum = currentSum + A[k]; maxEnd = k+1; }

 

if( currentMode == EXTEND && currentSum + A[k] < 0 ) { currentMode = RESET, currentSum = 0; }

 

源代码:

 

public class MaxSumArray {

 

          public static class Range {
                     int begin;
                     int end;

 

             public Range() {
                    begin = 0;
                    end = 0;
             }
  }

 

          public enum State {
                     RESET, EXTEND;
          }

 

 

          public static int getMaxSumArray(int[] array, Range range) {

  

                    State state = State.RESET;

 

                    int curBegin = 0;
                    int curEnd = curBegin + 1;
                    int curSum = 0;

 

                    int maxBegin = curBegin;
                    int maxEnd = curEnd;
                    int maxSum = array[0];

 

                    if (array[0] >= 0) {
                           curSum = array[0];
                           state = State.EXTEND;
                    }

 

                    for (int current = 1; current < array.length; current++) {

 

                           curSum += array[current];

 

                           if (state == State.RESET) {

                                // if in RESET, we treat every move as a possible range start
                                // so we need to remember this start position
                                curBegin = current;

                                if (curSum > maxSum) {

                                            // we can safely abandon the previous max range under RESET mode
                                            maxBegin = curBegin;

                                            curEnd = current + 1;

 

                                            // remember the new max range and value
                                            maxEnd = curEnd;
                                            maxSum = curSum;
                                }

 

                                 // if we switch from RESET to EXTEND, we do NOT need to reset curSum to 0
                                if (curSum > 0) {
                                            state = State.EXTEND;
                                 }

 

                                 if (state == State.RESET) {
                                             curSum = 0;
                                 }


                          } else { // if previous state is EXTEND

                                // under EXTEND mode, we do NOT need to change curBegin, neither maxBegin
   

                                 if (curSum > maxSum) {

                                             curEnd = current + 1;

                                             // remember the new max range and value
                                             maxEnd = curEnd;
                                             maxSum = curSum;
                                  }

    

                                  // Extend
                                  if (curSum < 0) {
                                            state = State.RESET;
                                            curSum = 0;
                                   }
                          }

                      }// end of for

 

                       range.begin = maxBegin;
                       range.end = maxEnd;

 

                       return maxSum;

           }

 

 

           public static void print(int[] array, int maxSum, Range range) {
                      System.out.println("Subarray with maxSum = " + maxSum + " is :");

                      for (int i = range.begin; i < range.end; i++) {
                                System.out.print(array[i] + "/t");
                      }

                      System.out.println();
           }

 

           public static void main(String[] args) {

  int[] given = { 1, -2, 3, 10, -4, 7, 2, -5 };

  Range range = new Range();
  int maxSum = getMaxSumArray(given, range);

  print(given, maxSum, range);

  int[] given2 = { -5, -2, -1, -3, -10 };
  maxSum = getMaxSumArray(given2, range);
  print(given2, maxSum, range);

          }

}
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值