输入一个整形数组(可能有正数和负数),求数组中连续子数组(最少有一个元素)的最大和。要求时间复杂度为O(n)。
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int[] nums = new int[N]; for (int i = 0; i < N; i++) { nums[i] = sc.nextInt(); } int max = nums[0],sum = 0; for(int i = 0;i < nums.length;i++){ sum += nums[i]; //更新 if(sum > max) max = sum; //sum并不是记录最大连续和,只记录大于零的和,只要连续和小于0 //则重新开始计算和,因为nums[i]加上一个负数肯定比它本身小 if(sum < 0){ sum = 0; } } System.out.println(max); } }
def largestSubSum(nums): for i in range(1,len(nums)): if nums[i-1] > 0: nums[i] = nums[i-1]+nums[i] return max(nums)
int maxSubArraySum(int[] a) { int biggestSum = 0, frameSetSum = 0; for (int i = 0; i <= a.length - 1; i++) { frameSetSum = frameSetSum + a[i]; //框集扩增 if(biggestSum < frameSetSum); { biggestSum = frameSetSum; //记录最大框集 } if (frameSetSum < 0) { frameSetSum = 0; //发现框集已不能使连续子数组和增大,框集前移 } return biggestSum; }算法2:
int maxSubArraySum(int[] a) { int frameSetSum = a[0]; int biggestSum = a[0]; for (int i = 1; i < a.length; i++) { frameSetSum = Math.max(a[i], frameSetSum + a[i]); //第一个变量大则框集前移,第二个变量大则框集扩增 biggestSum = Math.max(biggestSum, frameSetSum); //记录遍历过程中最大的子数组和 } return biggestSum; }可以看到,算法2中的两句max完全可以由算法1中的两个if替代。思路是完全一样的。
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = input.nextInt(); int[] dp = new int[n]; dp[0] = input.nextInt(); int res = dp[0]; for (int i = 1; i < n; i++) { int num = input.nextInt(); dp[i] = dp[i - 1] > 0 ? dp[i - 1] + num : num; res = Math.max(res, dp[i]); } System.out.println(res); } }
const readline = require('readline') const rl = readline.createInterface({ input: process.stdin, ouput: process.stdout }) let inArr = [] let n rl.on('line',line=>{ if(!line) return inArr.push(line.trim()) n = +inArr[0] if(inArr.length === n+1){ let arr = [] for (let i = 0; i < n; i++) { arr[i] = +inArr[i+1] } console.log(maxsum(arr)) } }) function maxsum(arr) { if(arr.length === 1){ return arr[0] } let max = 0, temp = 0 for (let i = 0; i < arr.length; i++) { temp += arr[i] max = Math.max(temp,max) if(temp<0){ temp = 0 } } return max }
比较容易想到的应该是动态规划吧,而且挺容易理解的。设dp[i]
表示这个连续子数组以索引i
结束时最大和。最后遍历填充完dp
后,真实的最大连续子数组和肯定以某个索引结束的,所以找到dp
中最大值即可。填充dp
时,如果dp[i-1] < 0
,那么dp[i]
直接等于第i
个数nums[i]
,否则就是dp[i] = dp[i-1] + nums[i]
。这个应该很容易理解。
int main () { int n = 0, temp = 0; cin >> n; vector<int> nums, dp(n, 0); while (cin >> temp) nums.push_back(temp); dp[0] = nums[0]; for (int i = 1; i < n; i++) { if (dp[i-1] < 0) dp[i] = nums[i]; else dp[i] = dp[i-1] + nums[i]; } cout << *max_element(dp.begin(), dp.end()) << endl; return 0; }
#include<iostream> #include<vector> #include<algorithm> using namespace std; int main(){ int N; vector<int> arr; while(cin>>N){ int tmp; //保存数组 for(int i=0;i<N;i++){ cin>>tmp; arr.push_back(tmp); } int dp[N];//动态规划 for(int i=0;i<N;i++){ if(i==0)dp[i]=arr[i]; else dp[i]=max(arr[i],dp[i-1]+arr[i]);//状态方程 } int max_rst=dp[0];//找最大和的值 for(int i=0;i<N;i++){ if(dp[i]>max_rst)max_rst=dp[i]; } cout<<max_rst<<endl; } }简单的动态规划
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; vector<int>num(n),dp(n,0); for(int i=0;i<n;i++) cin>>num[i]; dp[0]=num[0]; int res=dp[0]; for(int i=1;i<n;i++) { if(dp[i-1]+num[i]<0) dp[i]=0; else { dp[i]=dp[i-1]+num[i]; res=max(res,dp[i]); } } cout<<res<<endl; return 0; }
importjava.util.*; publicclassMain{ publicstaticvoidmain(String args[]){ Scanner cin = newScanner(System.in); //输入数组长度 intn = cin.nextInt(); int[] arr = newint[n]; //输入n行数据 for(inti=0;i<n;i++){ arr[i] = cin.nextInt(); } System.out.println(maxValue(arr,n)); } //求最大和 publicstaticintmaxValue(int[] arr,intn){ //创建数组dp,大小为arr数组大小 int[] dp = newint[n]; //dp[i]表示从arr[0]到arr[i]的最大和 dp[0] = arr[0]; intmaxValue = dp[0]; for(inti=1;i<n;i++){ //dp[i]的值可能为dp[i-1]+arr[i],也可能为arr[i],取最大值 dp[i] = Math.max(dp[i-1]+arr[i], arr[i]); if(dp[i]> maxValue){ maxValue = dp[i]; } } returnmaxValue; } } |
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int[] nums = new int[N]; for (int i = 0; i < N; i++) { nums[i] = sc.nextInt(); } int[] sums = new int[N]; sums[0] = nums[0]; int max = sums[0]; for (int i = 1; i < N; i++) { sums[i] = Math.max(nums[i], sums[i - 1] + nums[i]); max = Math.max(max, sums[i]); } System.out.println(max); } }
#include <bits/stdc++.h> using namespace std; int main() { int N; cin >> N; int sum = -1, temp = 0; for(int i = 0; i < N; i++) { int _; cin >> _; temp += _; if(temp < 0) { temp = 0; } else { sum = max(sum,temp); } } cout << sum << endl; return 0; }
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int[] arr = new int[N]; for(int i=0;i<N;i++){ arr[i] = scanner.nextInt(); } int[] sums = new int[N]; sums[0]=arr[0]; int max = 0; int min = 0; for(int i=1;i<N;i++){ sums[i] = sums[i-1]+arr[i]; max = sums[max]>sums[i]?max:i; min = sums[min]<sums[i]?min:i; } if(max>min){ int ret = sums[max]>sums[max]-sums[min]?sums[max]:sums[max]-sums[min]; System.out.println(ret); }else{ System.out.println(sums[max]); } } }