欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

剑指offer面试题42(java版):连续子数组的最大和

程序员文章站 2022-07-10 17:56:54
...

welcome to my blog

剑指offer面试题42(java版):连续子数组的最大和

题目描述

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

思路

  • 用sum记录连续n项的和, 当sum小于等于0时, 将sum重置为第n+1项的值, 继续向下遍历
  • 核心: 当sum小于等于0时要重置sum; 等于0是为了处理起始项, 最开始sum=0, 将起始项array[0]赋值给sum
        /*
        动态规划:
        令f(i)表示索引从0到i这段区间中的和的最大值, 对应代码中的currMax
        递推关系
            f(i) = f(i-1) + array[i]  if f(i-1)>0
            f(i) = array[i]  if f(i-1)<=0 or i==0
        */
        

动态规划(循环版1)

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        /*
        连续求了n个数的和, 如果这n个数的和小于等于0, 那么把第n+1个数赋给和. 因为连续的n+1数的和小于等于第n+1个数
        如果这n+1个数的和大于0, 那么把第n+1个数加到和上,直到遍历完数组或者和小于等于零才会重置和
        注意一点: 前面说"如果这n个数的和小于等于0", 为什么不限制为小于0,而是限制为小于等于0, 这是为了处理array[0]用的, sum初始值是0, 所以需要把array[0]赋值给sum
        注意一点: 这个思路没有讨论array[i]值的大小, 只通过观察sum的值进行状态的改变
        注意一点: sum是array[i]之前的连续n项和, 也就是根据sum的大小, 决定array[i]是加到sum上还是直接赋值给sum
        注意一点: 需要设置一个变量记录当前的最大值, 因为sum并不代表当前的最大值, 只是尽力维持连续n项和大于0
        */
        int sum = 0, currMax=Integer.MIN_VALUE;
        for(int i=0; i<array.length; i++){
            if(sum <= 0)
                sum = array[i];
            else //sum>0
                sum += array[i];
            if(sum > currMax)
                currMax = sum;
        }
        return currMax;
    }
}

动态规划(循环版2)

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        /*
        动态规划:
        令f(i)表示索引从0到i这段区间中的和的最大值
        递推关系
            f(i) = f(i-1) + array[i]  if f(i-1)>0
            f(i) = array[i]  if f(i-1)<=0 or i==0
        */
        int sum=0, max=Integer.MIN_VALUE;
        for(int i=0; i<array.length; i++){
            sum = Math.max(sum+array[i], array[i]); // 加sum与不加sum, 体现了动态规划的思想
            max = Math.max(sum, max);
        }
        return max;
    }
}

动态规划(递归版)

  • 需要控制index, sum, max
  • 循环版只用控制sum,max
  • 递归可能会产生大量重复子问题,导致时间效率和空间效率都不高
  • 注意在哪里返回
  • 注意递归中sum和max的处理, max稍微复杂一点
    • currMax=Core(array, index+1, sum+array[index], sum+array[index]>max?sum+array[index]:max);
    • currMax=Core(array, index+1, array[index], array[index]>max?array[index]:max);
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        /*
        动态规划:
        令f(i)表示索引从0到i这段区间中的和的最大值
        递推关系
            f(i) = f(i-1) + array[i]  if f(i-1)>0
            f(i) = array[i]  if f(i-1)<=0 or i==0
        */
        return Core(array, 0, 0, Integer.MIN_VALUE);
    }
    public int Core(int[] array, int index, int sum, int max){
        //recursion finish
        if(index==array.length)
            return max;
        //
        int currMax;
        if(index==0){
            currMax=Core(array, index+1, array[index], array[index]); //注意区分index++和index+1, index++会改变index的值, index+1不会改变index的值
        }
        else{ //index>0
            if(sum>0)
                currMax=Core(array, index+1, sum+array[index], sum+array[index]>max?sum+array[index]:max);
            else // sum<=0
                currMax=Core(array, index+1, array[index], array[index]>max?array[index]:max);
        }
        return currMax;
    }
}

上一篇: ClientService

下一篇: ddsd