LeetCode刷题之旅(简单-13):最大子序和

2019年6月8日

目录

题目:

解决方法1:暴力累计遍历法

思路:

性能结果:

解决方法2:动态规划

思路:

性能结果:

解决方法3:分治法(类似二分法)

思路:

性能结果:

解决方法4:其他网友的解法:利用中间数组过渡比较

思路:

性能结果:

小结:


题目:

LeetCode刷题之旅(简单-13):最大子序和_第1张图片

 

解决方法1:暴力累计遍历法


public class MaximumSubordinateSum {
    public static void main(String[] args){
        List list = new ArrayList<>();
        list.add(-2);
        list.add(1);
//        list.add(-3);
//        list.add(4);
//        list.add(-1);
//        list.add(2);
//        list.add(1);
//        list.add(-5);
//        list.add(4);
        int[] array = list.stream().mapToInt(Integer::intValue).toArray();
        int sum = maxSubArray(array);
        System.out.println("max = "+ sum);
    }


    public static int maxSubArray(int[] nums) {
        if (nums.length <= 0){
            return 0;
        }
        Integer max = nums[0];
        for (int i = 1 ; i max){
                max = temp;
            }
            for (int j= i+1;j max){
                    max = temp;
                }
            }
        }
        return max;
    }
}

思路:

  • 基于JDK8的stream,用mapToInt对于Integer元素转int,创建数组入参;
  • 时间复杂度:O(n) = n*n;肉眼可见,结果不尽人意。(O(n)姑且木有实现,分治呢?)

 

性能结果:

LeetCode刷题之旅(简单-13):最大子序和_第2张图片

解决方法2:动态规划


    /**
     * 主要是利用逐步求解,以连续数组结束位置为每一步的解,
     * sum其实就是记录了上一步骤的解,在这一步骤进行对比,如果上一步骤的解<0则舍弃。
     * 最终得到这一步骤解,与之前步骤解的最大值res进行比较,保存当前的最优解。
     * */
    public static int maxSubArrayV2(int[] nums) {
        int sum=0;
        int res=nums[0];
        // 1.一次遍历解决
        for(int num:nums){
            // 2.上次结果是否正数 ? 与新元素相加 : 取新元素
            sum=sum>0?(sum+num):num;
            // 3.该次结果与上次结果比较与赋值
            if(res

 

思路:

  • 主要是利用逐步求解,以连续数组结束位置为每一步的解,sum其实就是记录了上一步骤的解,在这一步骤进行对比,如果上一步骤的解<0则舍弃。最终得到这一步骤解,与之前步骤解的最大值res进行比较,保存当前的最优解。

  • 这道题根据题目关键词,“最大”“连续”,可以判断是一道动态规划。

 

性能结果:

性能提高明显。

LeetCode刷题之旅(简单-13):最大子序和_第3张图片

解决方法3:分治法(类似二分法)

 

    public static void main(String[] args){
        List list = new ArrayList<>();
        list.add(-2);
        list.add(1);
//        list.add(-3);
//        list.add(4);
//        list.add(-1);
//        list.add(2);
//        list.add(1);
//        list.add(-5);
//        list.add(4);
        int[] array = list.stream().mapToInt(Integer::intValue).toArray();
        int sum = maxSubArrayPart(array,0,array.length-1);
        System.out.println("max = "+ sum);
    }

    //-------------------分治法----------------------
    /**
     * 通过递归分治不断的缩小规模,问题结果就有三种,左边的解,右边的解,以及中间的解(有位置要求,从中介mid向两边延伸寻求最优解),
     * 得到三个解通过比较大小,等到最优解。
     * */
    private static int maxSubArrayPart(int[] nums,int left,int right){
        if(left==right){
            return nums[left];
        }
        int mid=(left+right)/2;
        return Math.max(
                maxSubArrayPart(nums,left,mid),
                Math.max(
                        maxSubArrayPart(nums,mid+1,right),
                        maxSubArrayAll(nums,left,mid,right)
                )
        );
    }

    //左右两边合起来求解
    private static int maxSubArrayAll(int[] nums,int left,int mid,int right){
        int leftSum=Integer.MIN_VALUE;
        int sum=0;
        for(int i=mid;i>=left;i--){
            sum+=nums[i];
            if(sum>leftSum){
                leftSum=sum;
            }
        }
        sum=0;
        int rightSum=Integer.MIN_VALUE;
        for(int i=mid+1;i<=right;i++){
            sum+=nums[i];
            if(sum>rightSum){
                rightSum=sum;
            }
        }
        return leftSum+rightSum;
    }

 

思路:

  • 通过递归分治不断的缩小规模,问题结果就有三种,左边的解,右边的解,以及中间的解(有位置要求,从中介mid向两边延伸寻求最优解),得到三个解通过比较大小,等到最优解。

  • 解法3的时间复杂度是nlog(n);

  • 分治的计算工作主要在中间部分的计算中, 左右部分的分治事实上没什么贡献;

 

性能结果:

解决方法4:其他网友的优秀解法

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

思路:

  • 拷贝nums到dp数组;
  • 从dp第二项开始,元素取(nums逐项)和(相邻两个元素之和)的最大值;其本质就是通过中间数组进行了一次相加(delta);(我感觉还是未能描述清楚作者的意图)

性能结果:

LeetCode刷题之旅(简单-13):最大子序和_第4张图片

 

小结:

只能说,好的代码,性能优化的非常好,思路也是新奇的很;多练习,多思考,从现在出发吧。

你可能感兴趣的:(LeetCode题库)