연속 부분 배열의 최대 합
정수 배열을 입력합니다. 배열에서 하나 이상의 연속 정수가 하위 배열을 형성합니다. 모든 하위 배열 합계의 최대 값을 찾습니다.
필요한 시간 복잡도는 O (n)입니다.
예 1 :
입력 : nums = [-2,1, -3,4, -1,2,1, -5,4]
출력 : 6
설명 : 연속 된 하위 배열 [4, -1,2,1]의 합은 다음과 같습니다. 가장 큰 것은 6입니다.
신속한:
1 <= arr.length <= 10 ^ 5
-100 <= arr [i] <= 100
동적 프로그래밍 분석 :
일반적인 아이디어 : 대상 배열 num과 동일한 크기로 동적 프로그래밍 배열 dp를 정의합니다. 순회 후 dp [i] 값은 요소 num [i]로 끝나는 연속 하위 배열의 최대 합입니다. 구현 원리 다음과 같다
상태 정의 :
1. 동적 프로그래밍 목록 dp, dp [i]가 요소 nums [i]로 끝나는 연속 하위 배열 의 최대 합을 나타냅니다 .
최대 합을 정의하는 이유 dp [i]는 요소 nums [i]를 포함해야합니다. dp [i]의 정확성을 dp [i + 1]에 재귀 적으로 보장하기 위해;
nums [i]가 포함되지 않은 경우 재귀 중에 질문의 연속 하위 배열 요구 사항이 충족되지 않습니다.
2. 전달 방정식 : dp [i-1] ≤0이면 dp [i-1]이 dp [i]에 음의 기여를한다는 것을 의미합니다. 즉, dp [i-1] + nums [i]는 nums [i]만큼 훌륭합니다.
dp [i-1]> 0 : 실행 dp [i] = dp [i-1] + nums [i];
dp [i -1] ≤0 일 때 : 실행 dp [i] = nums [i];
3. 초기 상태 :
dp [0] = nums [0], 즉 nums [0]으로 끝나는 연속 하위 배열의 최대 합은 nums [0]입니다.
4. 반환 값 :
전역 최대 값을 나타내는 dp 목록의 최대 값을 반환합니다.
public int maxSubArray1(int[] nums){
//暴力破解2优化,O(n^2)
int n = -100;
for (int i = 1; i < nums.length; i++) {
int sum = 0;
for (int j = i; j <= nums.length; j++){
sum += nums[j];
if (sum > n){
n = sum;
}
}
}
return n;
}
public int maxSubArray2(int[] nums){
//动态规划
//创建一个同样大小的数组dp[i]表示以元素num[i]为结尾的连续子数组最大和
int[] dp = new int[nums.length];
dp[0]=nums[0];//初始化dp[0]
for(int j = 1;j<nums.length;j++){
//判断条件,dp[j-1]>0表示以元素num[i]为结尾的连续子数组最大和大于0
// 即可对之后组成更大的连续子数组有正贡献
//dp[j-1]<0,表示以元素num[i]为结尾的连续子数组最大和小于0,
// 不再参与之后的连续子数组,子数组从新积累
if(dp[j-1]>0){
dp[j] = dp[j-1]+nums[j];
}else{
dp[j] = nums[j];
}
}
int max = Integer.MIN_VALUE;
for(int i = 0;i<dp.length;i++){
//遍历dp,找到最大值
if(dp[i]>max)
max = dp[i];
}
return max;
}
public int maxSubArray3(int[] nums) {
//同样的功能大佬的代码简单到离谱,阿巴阿巴
int res = nums[0];
for(int i = 1; i < nums.length; i++) {
nums[i] += Math.max(nums[i - 1], 0);
res = Math.max(res, nums[i]);
}
return res;
}
public class MaxSubArray {
public static void main(String[] args) {
Solution solution = new Solution();
int[] arr = new int[]{
-2,1,-3,4,-1,2,1,-5,4};//结果为6,ok
System.out.println(solution.maxSubArray3(arr));
}
}
요약 : 동적 프로그래밍 시작. 처음에는 가장 단순한 무차별 대입 솔루션조차 독립적으로 작성되지 않았습니다. 이제 이러한 문제를 해결하는 아이디어가 갑자기 명확 해졌고 이는 너무 강력합니다.
Brute force cracking은 0 [0], [0,1], [0,1,2]부터 [0,1,2, ... n까지 각 하위 배열 합계의 크기를 비교하는 이중 루프입니다. ], 시작 1, [1], [1,2], [1,2,3]에서 [1,2, ... n]까지, 그리고 2에서 시작합니다 ...
합계 (0,0) | ||
합계 (0,1) | 합계 (1,1) | |
합계 (0,2) | 합계 (1,2) | 합계 (2,2) |
합계 (0,3) | 합계 (1,3) | 합계 (2,3) |
… | … | … |
--------------------------------------->
이 문제의 동적 프로그래밍 아이디어는 num [i]로 끝나는 각 배열의 가장 큰 하위 배열을 찾아 배열 dp에 저장 한 다음 dp를 통과하여 최대 값을 찾는 것입니다.
최대 | |||
---|---|---|---|
합계 (0,0) | dp [0] | ||
합계 (0,1) | 합계 (1,1) | dp [1] | |
합계 (0,2) | 합계 (1,2) | 합계 (2,2) | dp [2] |
합계 (0,3) | 합계 (1,3) | 합계 (2,3) | dp [3] |
… | … | … | dp [j] |
최대 dp [j] 계산 방법
dp [j] = dp [j-1] + nums [j]; dp [j-1]> 0
dp [j] = nums [j]; dp [j-1] <0
이 방법은 스스로 주어진 예를 계산하여 이해할 수 있습니다.