Algorithm Design and Analysis [0009] Dynamic Programming (II) (Maximum Sum / Product Subarray)

Verbatim https://www.dazhuanlan.com/2019/08/25/5d625b5c4d1ea/


 This article 53. The the Maximum subarray & 152. The subarray the Maximum Product split and sub-problem solving: analysis of a key to solving the problem of dynamic programming ideas.

Problem Description

  • Two problems to solve similar problems are solved to the sequence given sequence to meet certain mathematical characteristics (maximum and / product of the maximum), even though not required the output sequence.
  • The key phrase is to pay attention to: containing at least one numberso there is at least a given sequence elements, which can also inspire us as special treatment.

53. Maximum Subarray problem-solving ideas

  • A thought: $ sums [j] $ is the largest sub-segment before the sequence j elements and sub-problems to solve as, the $ sum [n] $, compared with the answer. However, how to use the $ sums [1, 2, ..., j-1] $ to $ sums [j] $ solve it? Obviously need to know the maximum field and former j-element sub-segment start and end positions, solving the problem of sub-state transition is clearly more complicated.
  • Put it another thought. Two ideas: $ sums [j] $ is the maximum sub-segment with the first end of the j-th element of a child subsegment and problem solving, $ max_ {1 leq j leq n} (sums [j]) $ is the entire and the largest sub-segment sequences. Through $ sums [j-1] $ $ current element and the nums [j] can be calculated at $ j-th element is the largest sub-segment and ending $ sums [j] $, 状态转移方程as follows:
    $$ sums [j +. 1 ] = begin {cases} nums [ j + 1] sums [j] lt 0 cr sums [j] + nums [j + 1] others end {cases} $$
  • The two ideas, 53. the Maximum subarray to answer the following:
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
class  {
public:
int maxSubArray(vector<int>& nums) {
int SizeofNums = nums.size();
if(SizeofNums == 1) {
return nums[0];
}
int sums[SizeofNums];
sums[0] = nums[0];
for(int i=1; i<SizeofNums; i++) {

sums[i] = sums[i-1]<0 ? nums[i] : sums[i-1]+nums[i];
}


int largestSum = sums[0];
for(int i=1; i<SizeofNums; i++) {
if(largestSum < sums[i]) {
largestSum = sums[i];
}
}

return largestSum;
}
};
  • In order to obtain largestSumsequences corresponding to the variable that we can startIdxrecord the j-th element to the end ( endIdxstarting position) and the maximum sub-segment corresponding sub-sequence, $ nums [startIdx, ..., endIdx] $ is the corresponding sequence; Further, considering the current state and the previous state only relevant , it can be used instead of array variables, save memory, while avoiding acquire The largest sum of the whole arrayrepeated cycles of time.
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
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int SizeofNums = nums.size();
if(SizeofNums == 1) {
return nums[0];
}
// largest sum for the subarray ending with current element
int curSum = nums[0];
// largest sum of subarray for the whole array
int largestSum = curSum;
// subarray[startIdx, endIdx] with largest sum for the whole array
int startIdx = 0, endIdx = 0 ; for ( int i = 1 ; i <SizeofNums; i ++) { if (Cursor < 0 ) { cursor = nums [i]; startIdx = i; } Else { cursor speed + = nums [i]; } If (runner> largestSum) { largestSum = speed; endIdx = i; } } Return largestSum; } };


















152. Maximum Product Subarray problem-solving ideas

  • The problem solving process is substantially similar to the previous question, but the key problem to be solved is: the state transition, that is, how (max product to the j-th element is the end of the sub-segment) is calculated based on answers on a sub-problem the results of the current sub-problems.
  • 从上一题的分析可以看出,当前子问题(以第 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 = i;
}
}

return maxProduct;
}
};

Guess you like

Origin www.cnblogs.com/petewell/p/11408859.html