アルゴリズムの設計と解析[0009]動的計画法(II)(最大合計/製品サブアレイ)

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


 この記事53.最大サブアレー152サブアレー最大プロダクトスプリットとサブ問題解決:動的プログラミングのアイデアの問題を解決する鍵の分析。

問題の説明

  • 同様の問題点を解決するために、2つの問題は、出力シーケンスを必要としないにもかかわらず、特定の数学的特性(最大値と最大値の/生成物)を満たすように配列与えられた配列に解決されます。
  • キーフレーズは、に注意を払うことですcontaining at least one numberので、特別な治療法として私たちを鼓舞することができ、少なくとも所定の配列要素は、そこにあります。

53.最大サブアレイ問題解決のアイデア

  • 思想:$合計は[j]は$答えと比較し、$和[N] $、として解決するためのシーケンスjの要素と副問題前に最大サブセグメントです。しかし、どのように$の合計を使用するように、[1、2、...、J-1] $ $に合計[j]は$それを解決しますか?明らかに、最大フィールドと旧J-要素サブセグメントの開始位置と終了位置を知る必要があり、サブ状態遷移の問題を解決することは、明らかに、より複雑です。
  • それを別の思考を置きます。二つのアイデア:$和[J] $ $のMAX_ {1当量のj個の当量の、子サブセグメントと問題解決のj番目の要素の第一の端部で最大サブセグメントであり 、N}(合計[J])$が全体でありますそして、最大サブセグメント配列。$和[J-1] $ $現在の要素を通ってNUMS [j]は$のj番目の要素で計算することができる最大のサブセグメントと$和を終了する[J] $、であり状态转移方程、以下のように:
    。$$和[j個の+ 1 ] = {ケース} NUMS [開始 J + 1]和を[J] LT 0 CR和[J] + NUMS [J + 1]人が{ケース}を終了$$
  • 2つのアイデアは、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] =合計[I -1 ] < 0NUMS [I]:合計[I -1 ] + NUMS [I]。 }













INT largestSum =合計[ 0 ]。以下のためにint型 i = 1 ; iはSizeofNumsを<; iは++){ 場合(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を<; iは++){ 場合(カーソル< 0){ カーソル= NUMS [I]。 startIdx = I; } エルス { カーソル速度+ = NUMS [I]。 } の場合(ランナー> largestSum){ largestSum =速度; endIdx = I; } } 戻り 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 = I;
}
} 戻り maxProduct。 } }。




おすすめ

転載: www.cnblogs.com/petewell/p/11408859.html