给定一个长度为 的数组,数组中的数为整数。
请你选择一个非空连续子数组,使该子数组所有数之和尽可能大,子数组最小长度为1。求这个最大值。
第一行为一个正整数 ,代表数组的长度。第二行为 个整数 ,用空格隔开,代表数组中的每一个数。
连续子数组的最大之和。
8 1 -2 3 10 -4 7 2 -5
18
经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18
1 2
2
1 -10
-10
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]; }
总结:
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); } }
// 只讲一下核心代码,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; }