首页 > 试题广场 >

连续子数组最大和

[编程题]连续子数组最大和
  • 热度指数:27250 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个长度为 的数组,数组中的数为整数。
请你选择一个非空连续子数组,使该子数组所有数之和尽可能大,子数组最小长度为1。求这个最大值。

输入描述:
第一行为一个正整数 ,代表数组的长度。
第二行为 个整数 a_i,用空格隔开,代表数组中的每一个数。


输出描述:
连续子数组的最大之和。
示例1

输入

8
1 -2 3 10 -4 7 2 -5

输出

18

说明

经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18       
示例2

输入

1
2

输出

2
示例3

输入

1
-10

输出

-10
本题思路:
1.第一步,先获取到数组集合
2.第二步,如果数组只有一位数直接返回即可
3.第三步,我们定义dp数组的含义是存放子数组和最大值
4.第四步,确定最大值如何计算出来,因为是求子数组最大和,那么很容易想到有两种情况,添加当前值之前的数组和添加后相比哪一个更大,我们取最大的即可Math.max(sum,dp[i-1])
5.第五步,我们sum如何计算呢,又分两种情况,如果我们加了当前数比没加之前要小肯定就得放弃之前的方案,需要重新计算
6.第六步,返回dp[n-1]即可,因为我们定义的dp数组就是存放当前子最大和
        public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        int[] a = new int[num];
        for (int i = 0; i < num; i++) {
            a[i] = sc.nextInt();
        }
        int sum = 0;
        int max = getMaxPlus(sum, a);
        System.out.println(max);
    }

    private static int getMaxPlus(int sum, int[] a) {
        if (a.length == 1) return a[0];
        int[] dp = new int[a.length];
        dp[0] = a[0];
        if (dp[0] > 0) sum += dp[0];
        for (int i = 1; i < a.length; i++) {
            sum += a[i];
            sum = Math.max(sum, a[i]);
            dp[i] = Math.max(sum, dp[i - 1]);
        }
        System.out.println(Arrays.toString(dp));
        return dp[a.length - 1];
    }


发表于 2023-08-11 17:17:20 回复(0)

总结:
1.本题使用动态规划即可解出,很容易想到遍历到i个元素时,f[i-1]>0,f[i]=f[i-1]+arr[i];f[i-1]<0,f[i]=arr[i],其中f[i]是记录最后一个元素为arr[i]的最大连续子数组之和
2.由于计算f[i]只和上一个状态f[i-1]有关,所以只需记忆上一状态即可,空间复杂度可降为O(1)。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for(int i=0;i<n;i++){
            arr[i] = sc.nextInt();
        }
        int max,last;//max记录整个数组中最大之和,last记录包含上一个元素的最大连续子数组之和
        last = arr[0];
        max = last;
        for(int i=1;i<n;i++){
            if(last>0){
                last = last+arr[i];//包含当前元素的最大连续子数组之和
                max = Math.max(max,last);
            }else{
                last = arr[i];//包含当前元素的最大连续子数组之和
                max = Math.max(max,last);
            }          
        }
        System.out.println(max);
    }
}
发表于 2022-07-09 10:45:09 回复(2)
不可暴力循环,会超时。还是要动态规划当前最大值dp[i]=Math.max(ap[i-1]+arr[i],arr[i]) ;
发表于 2022-06-23 17:14:47 回复(0)
// 只讲一下核心代码,dp问题的关键就是找到状态转移方程也就是递推式 这里的ifelse就是
// 线性dp只考虑选或者不选两种操作是比较简单的思想,那么针对每一个数组中的元素,如果加上之前// 的还更小,那就不要之前的直接用arr[i],更大的话就加上即arr[i] + dp[i-1],递推出来
public static long getMax(int n, long[] arr) {
    long[] dp = new long[n];
    dp[0] = arr[0];
    long max = dp[0];
    for (int i = 1; i < arr.length; i++) {
        if (arr[i] + dp[i-1] > arr[i]) dp[i] = arr[i] + dp[i-1];
        else dp[i] = arr[i];
        max = Math.max(max, dp[i]);
    }
    return max;
}

发表于 2022-01-12 12:17:42 回复(0)

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        ArrayList<Integer> list1=new ArrayList<>();
        for(int i=0;i<n;i++){
        int k=scanner.nextInt();
        list1.add(k);
        }
        long cur=(long) -1e9;
        long maxx=(long) -1e9;
        for(Integer k:list1){
        cur=Math.max(k,k+cur);
            
        maxx=Math.max(cur,maxx);      
    }
       System.out.println(maxx);
  }
}
发表于 2021-10-28 21:53:17 回复(0)