面试题42-连续子数组的最大和(二)

题目:输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。

示例:
输入: nums = [1, -2, 3, 10, -4, 7, 2, -5]
输出: 18
解释: 连续子数组 [3, 10, -4, 7, 2] 的和最大,为 18。

题目分析:

经过一段时间的探索,这个题目除动态规划以及累加法【面试题42-连续子数组的最大和(一)】,这题也可以使用分治算法进行求解。

总体思想:将数组一分为二,我们在左边部分寻找一个最大的连续子数组和a,在右边部分寻找一个最大的连续子数组和b。也可能最大的连续子数组和处于中间阶段。即跨中间分界线而存在的一个子数组。如果是跨中间得话,一定包含左部分的最后一个元素,右部分的第一个元素(图中标红部分),所以为了寻找最大值,我们需要往左和右扩展,直到找到最大值c。整个数组的最大连续子数组,就是max(a,b,c)。如下图所示:
在这里插入图片描述

Java代码:
public class Offer42 {
    public static void main(String[] args) {
        int[] array1 = {1, -2, 3, 10, -4, 7, 2, -5};
        int[] array2 = {-2, -8, -1, -5, -9};
        int[] array3 = {};

        int result1 = maxSubArray(array1);
        int result2 = maxSubArray(array2);
        int result3 = maxSubArray(array3);

        int result11 = work(array1);
        int result22 = work(array2);
        int result33 = work(array3);

        System.out.print("累加法:result1"+"  ");
        System.out.println(result1);
        System.out.print("分治法:result11"+"  ");
        System.out.println(result11);
        
        System.out.print("累加法:result2"+"  ");
        System.out.println(result2);
        System.out.print("分治法:result22"+"  ");
        System.out.println(result22);

        System.out.print("累加法:result3"+"  ");
        System.out.println(result3);
        System.out.print("分治法:result33"+"  ");
        System.out.println(result33);
    }

    /**
     * 代理,构造递归
     * @param data
     * @return
     */
    private static int work(int[] data) {
        return f(data, 0, data.length);
    }

    /**
     * 二分法
     * @param data
     * @param begin
     * @param end
     * @return
     */
    private static int f(int[] data, int begin, int end) {
        // 判断数组是否为空。
        if ( data.length==0 || data==null){
            // System.out.println("数组为空");
            return 0;
        }
        // 递归出口
        if (end-begin==1){
            // 只剩下一个元素
            if (data[begin]>0){
                return data[begin];
            }else {
                return 0;
            }
        }
        int k = (begin+end)/2;
        // 临时变量,不包含k,左闭右开
        int t1 = f(data,begin,k);
        int t2 = f(data,k,end);
        // 中间扩展
        // 中间向左边扩展
        int t3a = 0;
        int sum = 0;
        for (int i = k-1; i>=begin; i--) {
            sum += data[i];
            if (sum>t3a){
                t3a = sum;
            }
        }
        // 中间向右边扩展
        int t3b = 0;
        sum = 0;
        for (int i = k; i<end; i++) {
            sum += data[i];
            if (sum>t3b){
                t3b = sum;
            }
        }
        int t3 = t3a+t3b;
        // 求三个数的最大值。
        int max = 0;
        if (t1>max){
            max = t1;
        }
        if (t2>max){
            max = t2;
        }
        if (t3>max){
            max = t3;
        }
        return max;
    }

    public static int maxSubArray(int[] nums) {
        // 判断数组是否为空。
        if ( nums.length==0 || nums==null){
            // System.out.println("数组为空");
            return 0;
        }
        int sum = nums[0];
        int max = sum;
        for (int i = 1; i < nums.length; i++) {
            if (sum<=0){
                sum = nums[i];
            }else {
                sum += nums[i];
            }
            if (sum>max){
                max = sum;
            }
        }
        return max;
    }
}
运行结果:

运行结果

【注】
(1):leetcode 等平台只要我们完成一个函数即可,本人初出茅庐,为了巩固基本知识,故自己补充了部分代码,用于练手。本代码也许存在漏洞,望高手赐教。感谢!
(2):认真观察后,会发现对于第二个数组的结果存在差异。原因是分治法中,如果对于小于0的数,返回的是0。什么都不取。而另外一个算法,其实暗含要求最少取一个值的意思。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值