逐語 https://www.dazhuanlan.com/2019/08/25/5d625b5c4d1ea/
この記事 53.最大サブアレー & 152サブアレー最大プロダクト スプリットとサブ問題解決:動的プログラミングのアイデアの問題を解決する鍵の分析。
問題の説明
同様の問題点を解決するために、2つの問題は、出力シーケンスを必要としないにもかかわらず、特定の数学的特性(最大値と最大値の/生成物)を満たすように配列与えられた配列に解決されます。
キーフレーズは、に注意を払うことです containing at least one number
ので、特別な治療法として私たちを鼓舞することができ、少なくとも所定の配列要素は、そこにあります。
思想:$合計は[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 ] < 0 ? NUMS [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。 INT startIdx = 0 、endIdx = 0 ; 以下のために ( int型 i = 1 ; iはSizeofNumsを<; iは++){ 場合 (カーソル< 0 ){ カーソル= NUMS [I]。 startIdx = I; } エルス { カーソル速度+ = NUMS [I]。 } の場合 (ランナー> largestSum){ largestSum =速度; endIdx = I; } } 戻り largestSum。 } }。
プロセスを解く問題は、以前の質問に実質的に類似しているが、解決すべき重要な問題がある:状態遷移、すなわち、サブ問題に回答に基づいて計算される方法(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 ]; } int maxProducts[SizeofNums]; int minProducts[SizeofNums]; maxProducts[0 ] = minProducts[0 ] = nums[0 ]; for (int i=1 ; i<SizeofNums; i++) { maxProducts[i] = max( max(maxProducts[i-1 ]*nums[i], minProducts[i-1 ]*nums[i]), nums[i]); minProducts[i] = min( min(maxProducts[i-1 ]*nums[i], minProducts[i-1 ]*nums[i]), nums[i]); } 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 ]; } int largestProduct = nums[0 ]; int leastProduct = nums[0 ]; int maxProduct = largestProduct; int startIdx = 0 , endIdx = 0 ; int startIdx_pos = startIdx, startIdx_neg = startIdx; for (int i=1 ; i<SizeofNums; i++) { int largestProduct_pre = largestProduct; int leastProduct_pre = leastProduct; largestProduct = max( max(largestProduct_pre*nums[i], leastProduct_pre*nums[i]), nums[i]); if ((largestProduct_pre != nums[i]) && (largestProduct == nums[i])) { startIdx_pos = i; } 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。 } }。