zoukankan      html  css  js  c++  java
  • 53. Maximum Subarray

    题意是求最大子序列和
    input:[−2,1,−3,4,−1,2,1,−5,4]
    ans:6 [4,−1,2,1]
    下面给出三种不同时间复杂度的解法。

    一. O(N^2)
    两个point,一个指向子序列的头,一个指向子序列的尾,两层循环求该子序列的和。

    public class Solution {
        public int maxSubArray(int[] nums) {
            int max = nums[0];
            for(int i = 0; i < nums.length; i++) {
                int temp = 0;
                for(int j = i; j < nums.length; j++) {
                    temp += nums[j];
                    max = temp > max ? temp : max;
                }
            }        
            return max;
        }
    }

    二. O(N*logN)
    步骤如下:
    1.取数组的中间元素mid(向下取整),最大子序列无非存在两种情况:
      1.1跨越中间元素
        最大子序列中一定存在mid和mid+1(由于mid向下取整,mid+1<=right),那么就从mid向左计算左最大值,从mid+1向右计算右最大值。这种情况的结果是左最大值加右最大值。
      1.2不跨越中间元素
        将原数组分为两个部分:[left, mid], [mid+1, right],对这两个数组再次使用步骤1。
    这种方法是分治法(Divide and Conquer),用递归实现,一般取中间值的算法,复杂度都跟logN有关。

    public class Solution {
        public int maxSubArray(int[] nums) {
            return helper(nums, 0, nums.length - 1);
        }
    
        private int helper(int[] nums, int left, int right) {
            if(left == right) return nums[left];        
            int mid = left + ((right - left) >> 1);
            int leftMax = helper(nums, left, mid);
            int rightMax = helper(nums, mid + 1, right);
            int tempSum = 0;
            int maxL = nums[mid];
            int maxR = nums[mid+1];
            for(int i = mid; i >= left; i--) {
                tempSum += nums[i];
                maxL = Math.max(tempSum, maxL);
            }
            tempSum = 0;
            for(int i = mid + 1; i <= right; i++) {
                tempSum += nums[i];
                maxR = Math.max(tempSum, maxR);
            }
            return Math.max(Math.max(leftMax, rightMax), maxL + maxR);
        }
    }

    三. O(N)
    最大子序列算是动态规划(Dynamic Programming)的一个经典例题。通常我们需要找到一个递推公式。设max(nums, i)是以nums[i]为结尾(该序列中一定包含nums[i],且以nums[i]结尾)的最大子序列和,递推式为:

    max(nums, i) = (max(nums, i-1) < 0 ? 0 : max(nums, i-1)) + nums[i];

    由于一定要包含nums[i],那么就不必考虑nums[i]是大于0还是小于0。要考虑的是nums[i]前面的序列,如果前面的序列大于0,就要它;如果小于0,就不要它。由于定义了DP数组,空间复杂度为O(N)。

    public class Solution {
        public int maxSubArray(int[] nums) {
            int[] DP = new int[nums.length];
            int max = nums[0];
            DP[0] = nums[0];
            for(int i = 1; i < nums.length; i++) {
                DP[i] = (DP[i-1] < 0 ? 0 : DP[i-1]) + nums[i];
                max = Math.max(max, DP[i]);
            }
            return max;
        }
    }

    一般来说,可以通过优化动态规划中的数组来优化空间复杂度。从for循环中的递推式可以看到:

    DP[i] = (DP[i-1] < 0 ? 0 : DP[i-1]) + nums[i];

    每次循环只需要上一次的DP值,那么我们就不需要定义DP数组了,空间复杂度可以降低到O(1)。

    //空间复杂度O(1)
    public class Solution {
        public int maxSubArray(int[] nums) {
            int DP = nums[0];
            int max = nums[0];
            for(int i = 1; i < nums.length; i++) {
                DP = (DP < 0 ? 0 : DP) + nums[i];
                max = Math.max(max, DP);
            }
            return max;
        }
    }

    四. 注意事项
    1.程序中类似于max变量的初始化不能为0,因为序列有可能全是负值,0大于负值,这样最后的结果会是0。
    2.对于一种类型的题目,最好能知道不同复杂度的解法,面试也从最简单的解法入手,然后一步一步去优化。

  • 相关阅读:
    JavaScript DOM API初步(整理)
    MySQL与Oracle之间互相拷贝数据的Java程序
    MySQL与Oracle的区别之我见
    js原生:封装document.getElementByClassName()函数
    js和jquery获取父级元素、子级元素、兄弟元素的方法
    封装bt轮播图淡入淡出效果样式
    Bootstrap每天必学之导航条
    全面解析Bootstrap图片轮播效果
    JS如何获取页面可见区域高度
    怎样才能成为优秀的前端工程师
  • 原文地址:https://www.cnblogs.com/season-peng/p/6713492.html
Copyright © 2011-2022 走看看