• leetcode第53题——最大子序和


    题目:

    给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    示例:

    输入: [-2,1,-3,4,-1,2,1,-5,4],
    输出: 6
    解释: 连续子数组 [4,-1,2,1] 的和最大,为 6

    初次拿到这个题目,最直接的想法是:遍历整个数组,求其所有的子序列,然后找最大的。其大致思路自然是用两个索引i,j,然后获取i,j之间的数组的值,然后用打擂台法获取最大的;这种方法的时间复杂度是o(n^2)。

    有没有更好的办法?或者说我们能不能找到一种策略,使得下一次的结果一定比上次大,这样我们只需要遍历一次数组就可以?

    当然有,这种思想就是:如果当前序列和为负数,那么下一个寻找开始的位置。就不再包含当前位置及以前位置的数,!

    我们借助这个思想分析一下上述示例数组:[-2,1,-3,4,-1,2,1,-5,4],

     1 第一次:当前序列和sum = -2<0;因此不再考虑位置0的数
     2 第二次:当前序列和sum = 1  >0;则当前最大和max_sum = 1;考虑位置1的数
     3 第三次:当前序列和sum = 1+-3 = -2<0;因此不再考虑-3以前的数;
     4 第四次:当前序列和sum = 4>0;则当前最大和sum_max = 4;此时最大序列为4;
     5 第五次:当前序列和sum = 4+-1=3>0;则当前最大和sum_max = 4;此时最大序列为4;但由于sum>0,我们仍然需要考虑将4作为起始点
     6 第六次:当前序列和sum = 4+-1+2 = 5>0;当前最大序列和sum_max = 5;此时最大序列[4,-1,2];
     7 第七次:当前序列和sum = 4+-1+2+1 = 6>0;当前最大序列和sum_max = 6;此时最大序列[4,-1,2,1];
     8 第八次:当前序列和sum =  4+-1+2+1 +-5 = 1>0;sum_max = 6;此时最大序列[4,-1,2,1];
     9 第九次:当前序列和sum =  4+-1+2+1 +-5+4 = 5>0;sum_max = 6,此时最大序列为
    10 [4,-1,2,1];
    11 结束!

    就这样,当我们遍历完数组的时候,最大子序列就找到了;可见时间复杂度是O(n);

    在这里有人也许会问:上述只是从位置3的元素4遍历到了结尾。会不会存在从位置3后面开始,到某个位置的数比从元素4开始的序列[4,-1,2,1]序列和更大?

    显然不会,为何?因为我们说过,只要当前序列和<0,我们就舍弃之前所有的位置;而序列和>0,我们就保留那些位置。因此,我们保留了从4开始的位置。说明了序列和是大于0的;而从4后面开始,显然是从4开始的序列的子集,其和不可能大于从4开始。

    那么上述思路有一个明显的漏洞是:如果当前序列和为负数,从下一个位置开始,不再包含当期所有位置;显然如果数组所有元素都是负数。那么我们最终是找不到一个最大和子序列的;但是我们知道如果一个序列全是负数,最大子序列就是其中最大的负数,因此,我们应该单独考虑全为负数的情况。

    那么我们怎么考虑一个数组全部为负数呢?很简单,如果一个数组的最大元素为负数,那么整个数组就为负数。因此,我们可以给出完整的求最大子序列的代码:

     1 class Solution {
     2 public:
     3     int maxSubArray(vector<int>& nums) {
     4         int max = 0,temp = 0;
     5         int allnegative_max = nums[0];
     6     for (int i = 0; i < nums.size(); i++) {
     7         temp += nums[i];
     8         if (temp < 0)
     9             temp = 0;
    10         if (max < temp)
    11             max = temp;
    12         if(nums[i] > allnegative_max)
    13            allnegative_max = nums[i];//用于判断是否全部为负数
    14     }
    15     if(allnegative_max < 0)//说明数组全部为负数
    16       return allnegative_max;
    17     else
    18     return max;
    19     }
    20 };

    当然了,这个题目可以进一步的提问:找到最大和子序列的起始位置?那么又该如何编码呢?

    class Solution {
    public:
        int maxSubArray(vector<int>& nums) {
            int max = 0,temp = 0;
            int start1,start2;
            int allnegative_max = nums[0];
        for (int i = 0; i < nums.size(); i++) {
            temp += nums[i];
            if (temp < 0)
            {
                temp = 0;
                start1 = i+1;
            }
            if (max < temp)
                max = temp;
            if(nums[i] > allnegative_max)
            {
               allnegative_max = nums[i];//用于判断是否全部为负数
               start2 = i;
            }
        }
        if(allnegative_max < 0)//说明数组全部为负数
          return allnegative_max;
        else
        return max;
        }
    };

    其中start1和start2表明了位置

  • 相关阅读:
    Linux/Android 系统怎么修改mac地址
    Vue.js和jQuery混合使用的一点注意事项
    wpf研究之道——datagrid控件及样式
    asp.net url重写
    如何解决一个问题
    Word 2007 封面、目录和正文页码单独设置
    .net 多线程
    我对asp.net运行机制的理解
    Firefox扩展安装
    谷歌chrome 插件(扩展)开发——谈谈安装
  • 原文地址:https://www.cnblogs.com/shaonianpi/p/12736005.html
Copyright © 2020-2023  润新知