面试题42:连续子数组的最大和

题目:

输入一个整型数组,数组里面有正数也有负数。数组中的一个或连续多个整数组成一个子数组。其所有子数组的和的最大值。要求时间复杂度为O(n)。例如,输入的数组为{1,-2,3,10,-4,7,2,-5},和最大的子数组是{3,10,-4,7,2},子数组的和为18。

分析:

举例分析数组的规律

我们试着从头到尾逐个累加数组中的每个数字,初始化为0,第一步加上数字1,此时和为1,第二步加上数字-2,此时和为-1.第三步加上数字3,此时和为2。我们注意到由于此前累加的和为-1,小于0,用-1加上3得到的是2,比3本身还小,于是从第一个数字开始的子数组的和一定小于从第三个开始的子数组的和。

从三个数字开始累加,此时和为3,第四步加上数字10,此时和为13。第五步加上数字-4,此时和为9,小于之前的13,于是我们要把13给保存下来。第六步加上数字7,此时和为16,比13要大,就把之前的13更新为16,继续向后操作。

应用动态规划法

我们定义一个函数f(i)表示,以第i个数字为结尾的子数组的最大和,那么,当i∈[0, length - 1]的时候,求出所有的f(i)再取一个max,就可以得到最大值了。我们可以得出一个递推表达式。

当以第i-1个数字结尾的子数组中所有数字和小于0时,如果把这个负数和第i个数累加,结果比第i个数本身还要小,这种情况,以第i个数字为结尾的子数组就是第i个数字本身。如果以第i-1个数字结尾的子数组中所有数字的和大于0,则第i个数字累加就得到以第i个数字结尾的子数组中所有数字的和。

解法:

举例分析数组的规律

package com.wsy;

public class Main {
    public static void main(String[] args) {
        int[] array = new int[]{1, -2, 3, 10, -4, 7, 2, -5};
        findGreatSumOfSubArray(array);
    }

    public static void findGreatSumOfSubArray(int[] array) {
        if (array == null) {
            return;
        }
        int length = array.length;
        int sum = 0;
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < length; i++) {
            if (sum <= 0) {
                sum = array[i];
            } else {
                sum += array[i];
            }
            if (sum > max) {
                max = sum;
            }
        }
        System.out.println("连续子数组的最大和为:" + max);
    }
}

应用动态规划法

package com.wsy;

public class Main {
    public static void main(String[] args) {
        int[] array = new int[]{1, -2, 3, 10, -4, 7, 2, -5};
        findGreatSumOfSubArray(array);
    }

    public static void findGreatSumOfSubArray(int[] array) {
        if (array == null) {
            return;
        }
        int length = array.length;
        int[] sumOfSubArray = new int[length];
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < length; i++) {
            if (i == 0 || sumOfSubArray[i - 1] <= 0) {
                sumOfSubArray[i] = array[i];
            }
            if (i != 0 && sumOfSubArray[i - 1] > 0) {
                sumOfSubArray[i] = sumOfSubArray[i - 1] + array[i];
            }
            if (sumOfSubArray[i] > max) {
                max = sumOfSubArray[i];
            }
        }
        System.out.println("连续子数组的最大和为:" + max);
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值