leetcode53Maximum Subarray

124 阅读1分钟

一 题目

在数组中找一个子数组,子数组的每一个元素之和最大并且返回这个数字。

二 滑动窗口实现

    可以定义两个指针l和r,分别确定子数组的左右边界。
    假设子数组所有元素的和sum,当sum<nums[r]时,说明sum一定不是最优解,
    但此时也不能简单粗暴的确定最优值一定是nums[r],
    比如这种情况[-6,1,2,2,1],数组总和0小于1,但是此时1也明显不是子数组中元素和最大值。
    因此sum<nums[r]只能说明当前子数组一定不是最优解,不能说明nums[i]一定是最优解。
    同时当前子数组中的其他子集依旧有可能包含最优解,因此应该将左指针l右滑即可。
    var maxSubArray = function(nums){
        let l=0;
        let r=0;
        let max=nums[0];
        let sum=nums[0];
        while(l<nums.length&&r<nums.length){
            if(sum<nums[r]){
               max=Math.max(sum,max);
               sum-=nums[l++];
            }else if(sum>=nums[r]){
               max=Math.max(sum,max);
               sum+=nums[++r];
            }
        }
        return max;
    }

三 动态规划

  1. 动态规划在查找有很多重叠子问题的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题,它们的结果都逐渐被计算并被保存,从简单的问题直到整个问题都被解决。因此,动态规划保存递归时的结果,因而不会在解决同样的问题时花费时间。
  2. 动态规划只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。
  3. 实现
    以[-2,1,-3,4,-1,2,1,-5,4]为例,用数组中第i项fn[i]记录数组nums[0...i]的最优解。自下而上解决问题。
    fn[0]记录nums[0...0]的最优解,即fn[i]=nums[0]=-2。
    接着用fn[1]记录nums[0...1]的最优解,
    而fn[1]=Math.max(nums[1],nums[1]+fn[0])
    即fn[1]=Math.max(1,-1)=1。
    接着用fn[2]记录nums[0...2]的最优解,
    而fn[2]=Math.max(nums[2],nums[2]+fn[1])
    即fn[2]=Math.max(-3,-2)=-2。
    以此类推...
    var maxSubArray = function(nums){
        let fn=[nums[0]];
        for(let i=1;i<nums.length;i++){
            fn[i]=Math.max(nums[i],fn[i-1]+nums[i]);
        }
        return Math.max(...fn);
    }