알고리즘 설계 및 분석 [0009] 동적 프로그래밍 (II) (최대 합계 / 제품 부분 배열)

축 어적으로 https://www.dazhuanlan.com/2019/08/25/5d625b5c4d1ea/


 이 문서 (53) 최대 부분 배열152 부분 배열 최대 제품 분할 및 하위 문제 해결 : 동적 프로그래밍 아이디어의 문제를 해결하는 열쇠의 분석.

문제 설명

  • 유사한 문제를 해결하기위한 두 가지 문제는 출력 시퀀스가 ​​필요하지 않더라도, 소정의 수학적 특성 (최대 및 최대 / 상품)를 만족하는 시퀀스 주어진 서열에 해결된다.
  • : 키 문구에주의를 기울여야하는 것입니다 containing at least one number그래서도 우리와 같은 특수 치료를 영감을 수있는 적어도 주어진 시퀀스 요소가있다.

53 최대 부분 배열의 문제 해결 방안

  • 생각 : $ 합은 [J]를 $ 해답과 비교하여 $ 합 [N] $로 해결 시퀀스 J 요소 및 서브 문제 전에 최대 서브 세그먼트이다. 그러나, 방법 $ 합을 사용하여, [1, 2, ..., J - 1] $ $을 합계 [J]를 $ 그것을 해결? 분명히 분명히 하위 상태 전이의 문제를 해결, 최대 필드 전 J-요소 하위 세그먼트의 시작과 끝 위치를 알고 더 복잡합니다.
  • 그것은 또 다른 생각을 넣습니다. 두 아이디어 : $ [j]가 $ 아이 서브 세그먼트 및 문제 해결, $의 MAX_ {1 당량 J의 당량에의 j 번째 엘리먼트의 상기 제 1 단부와 최대 서브 세그먼트이고 합계 N} (합계 [J]) $가 전체이며 가장 큰 서브 세그먼트 시퀀스. $ 합 스루 [J-1] 현재 요소와 nums [J]를 $의 j 번째 엘리먼트의 최대 서브 세그먼트이고 계산 종료 $ 합 [J] $ 될 수 $ $ 状态转移方程다음과 같다
    . $$ 합계 [j 개의 + 1 = {이 경우} nums 시작 [ J + 1] 합계 [J] LT 0 CR 합 [J] + nums [J + 1] 다른 케이스 {} 최종 $$
  • 두 개의 아이디어는, 53 최대 부분 배열은 다음과 같은 답변을 :
1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
클래스   { 
공개 : INT maxSubArray ( 벡터 < INT > & nums) { INT SizeofNums nums.size = (); 경우 (SizeofNums == 1 ) { 리턴 nums [ 0 ]; } INT의 합 [SizeofNums]; 합 [ 0 ] = nums의 [ 0 ]; ( int로는 I = 1 ; i가 SizeofNums를 <; 내가 ++) { 합계 [I] = 합계 [I -1 ] < 0 ? nums [내가] 합계 [I -1 ] + nums [I]; }













INT largestSum는 합계 = [ 0 ]; 위한 ( int로 I = 1 ; i가 SizeofNums를 <; 내가 ++) { 경우 (largestSum <합 [I]) { largestSum = 합계를 [I]; } } 반환 largestSum을; } };









  • 얻기 위해 largestSum우리가 할 수있는 변수에 대응하는 시퀀스 startIdx끝 j 번째 엘리먼트를 기록 ( endIdx개시 위치) 및 최대 서브 세그먼트에 대응하는 서브 시퀀스 $의 nums를 [startIdx는 ... endIdx] $는 해당 순서이고; 또한, 고려 현재 상태에만 관련된 이전 상태를 , 그 취득 회피하면서, 메모리를 절약하는 대신 배열 변수를 사용할 수있는 The largest sum of the whole array시간의주기를 반복.
1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
클래스  해결 { 
공개 : INT maxSubArray ( 벡터 < INT > & nums) { INT SizeofNums nums.size = (); 경우 (SizeofNums == 1 ) { 리턴 nums [ 0 ]; } 현재 요소 끝 부분 배열 용 // 최대 합 INT curSum nums = [ 0 ]; 전체 어레이 배열의 // 최대 합 INT largestSum = curSum; // 서브 어레이 [startIdx, endIdx] 전체 어레이의 최대 합 INT startIdx = 0 , = endIdx










0 ; 위한 ( int로 I = 1 ; i가 SizeofNums를 <; 내가 ++) { 경우 (커서 < 0 ) { 커서 nums = [I]; startIdx = 1; } 그렇지 { 커서 속도 + = nums [I]; } 인 경우 (주자> largestSum) { largestSum = 속도; endIdx = 1; } } 반환 largestSum을; } };


















(152) 최대 제품 부분 배열의 문제 해결 방안

  • 문제 해결 과정 이전 질문과 실질적으로 유사하지만, 해결해야 할 주요 문제는 다음 상태 전이, 즉 (j 번째 엘리먼트의 최대 제품 서브 세그먼트의 마지막 인) 방법이며,이 서브 문제에 대한 대답에 기초하여 계산된다 현재의 서브 - 문제의 결과.
  • 从上一题的分析可以看出,当前子问题(以第 j 个元素为结尾的子段的max sum)的计算只需考虑上一个子问题的结果 $sum[j-1]$,$sum[j-1] < 0$,因为是加法,显然可以将子问题结果忽略;$sum[j-1] > 0$,$sum[j-1]$ 加上当前元素就是当前子问题的结果。
  • 类似的问题,只不过换成乘积,子问题的求解就变得复杂了,需要考虑以下几种情况:
    • 当前元素是正数,max product可能是正正得正的情况,因为都是整数,乘积>1,上一子问题的结果乘上当前元素即为当前子问题的答案
    • 当前元素是负数,max product可能是负负得正的情况,因此需要维护以第 j 个元素为结尾的子段的min product(很大可能是负数)
    • 另外,需要考虑上一个子问题的结果为0的情况
    • 总之,乘积的最大值为上述三种情况之一
      状态转移方程如下:
      $$ maxProducts[j+1] = max(maxProducts[j-1]*nums[j], minProducts[j-1]*nums[j], nums[j])$$
  • 152. Maximum Product Subarray 解答如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
int maxProduct(vector<int>& nums) {
int SizeofNums = nums.size();

if(SizeofNums == 1) {
return nums[0];
}
// The largest/least product of subarray ending with the i-th element
int maxProducts[SizeofNums];
int minProducts[SizeofNums];
maxProducts[0] = minProducts[0] = nums[0];
for(int i=1; i<SizeofNums; i++) {
// positive with positive, negative with negative, ignore previous zero
maxProducts[i] = max( max(maxProducts[i-1]*nums[i], minProducts[i-1]*nums[i]), nums[i]);
// positive with negative, negative with positive, ignore previous zero
minProducts[i] = min( min(maxProducts[i-1]*nums[i], minProducts[i-1]*nums[i]), nums[i]);
}

// getting the largest product for the whole array
int largestProduct = maxProducts[0];
for(int i=1; i<SizeofNums; i++) {
if(maxProducts[i] > largestProduct) {
largestProduct = maxProducts[i];
}
}

return largestProduct;
}
};
  • 与上一题类似,添加额外变量,也能实现节省内存,记录子段最大乘积对应子段($nums[startIdx, endIdx]$)的起始和终止位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
public:
int maxProduct(vector<int>& nums) {
int SizeofNums = nums.size();

if(SizeofNums == 1) {
return nums[0];
}
// The largest/least product of subarray ending with the i-th element
int largestProduct = nums[0];
int leastProduct = nums[0];
// The largest product for the whole array
int maxProduct = largestProduct;
// subarray[startIdx, endIdx] with largest product for the whole array
int startIdx = 0, endIdx = 0;
// start index for largestProduct/leastProduct
int startIdx_pos = startIdx, startIdx_neg = startIdx;

for(int i=1; i<SizeofNums; i++) {
int largestProduct_pre = largestProduct;
int leastProduct_pre = leastProduct;

// positive with positive, negative with negative, ignore previous zero
largestProduct = max( max(largestProduct_pre*nums[i], leastProduct_pre*nums[i]), nums[i]);
if((largestProduct_pre != nums[i]) && (largestProduct == nums[i])) {
startIdx_pos = i;
}

// positive with negative, negative with positive, ignore previous zero
leastProduct = min( min(largestProduct_pre*nums[i], leastProduct_pre*nums[i]), nums[i]);
if((leastProduct_pre != nums[i]) && (leastProduct == nums[i])) {
startIdx_neg = i;
}

if(largestProduct > maxProduct) {
maxProduct = largestProduct;
if(largestProduct_pre*nums[i] > leastProduct_pre*nums[i]) {
startIdx = startIdx_pos;
}
else {
startIdx = startIdx_neg;
}
endIdx = 1;
}
} 반환 maxProduct을; } };




추천

출처www.cnblogs.com/petewell/p/11408859.html