多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > [LeetCode] Maximum Product Subarray的兩種思路

[LeetCode] Maximum Product Subarray的兩種思路

來源:程序員人生   發布時間:2014-10-08 09:33:02 閱讀次數:2788次

Find the contiguous subarray within an array (containing at least one number) which has the largest product.

For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.


這題和之前的一題Maximum Subarray非常類似,一個是求最大和,而這個是求最大乘積。可以用大致類似的思路解,但是求乘積比求和要復雜些,多了不少corner case,一次寫完沒bug還是很難的。不過這題出得還算仁慈,因為這題其實有兩個地方簡化了:

1)注意這里的數組是整型的,如果含有浮點數,就有可能出現0-1之間類似0.25這樣的小數,所以即使是全都是正數,也可以越乘越小。如果數組里的數字全為正數還好說,因為可以用求對數的方式把求乘積轉化為求和,從而轉換為之前的Maximum Subarray。但是因為這題有負數和0的存在,所以求對數的方法行不通。

2)這題的測試用例里數組元素的絕對值都非常的小,而實際中如果真的連乘起來,最后數值越界很容易發生的。如果考慮這一點,要么估計得用類似Java里BigInteger類這樣的東西去避免越界。


言歸正傳,這題我覺得至少有兩種思路求解。

思路一:類似Maximum Subarray的解題思路,在遍歷過程中,不斷更新以當前元素為終點的subarray的乘積極大值(下面簡稱極大值)和最大值。本質上無非就是要做出一個二選一:要么繼續把當前遍歷的元素算上,擴展當前的subarray,要么就重新開始一個subarray。此外,如何更新最大值?由于有整數,負數和0的存在,需要分為三種情況,并且還需要維護一個極小值。為了方便連乘操作,這里規定維護的最大乘積必須大于等于1,即不能等于0。另外需要注意,在沒有遍歷到負數之前,極小值這里其實和極大值是一樣大的(不考慮為0的情況),也可以是正數。


綜合考慮如下:

1)如果當前元素為正數,那么極大值只可能擴大,所以應該繼續擴展當前subarray:

此種情況簡單,極大值應該更新為原極大值乘以當前元素,極小值更新為原極小值乘以當前元素。全局最大值跟極大值比較。

2)如果當前元素為負數,那么極大值可能會變小,所以不清楚應該繼續擴展當前subarray還是新起一個subarray:

對于極大值的更新:如果擴展當前subarray,極大值為原極小值乘以當前元素;如果另外新起一個subarray,由于當前元素為負數,所以直接舍棄,根據規定,設為初始值1。由于這里原極小值不一定為負數,所以前者和后者之間比較沒有絕對的誰大。

對于極小值的更新:如果擴展當前subarray,極小值為原極大值乘以當前元素;如果另外新起一個subarray,極小值為當前元素。不過由于之前極大值肯定大于1,所以前者肯定比后者大,所以極小值更新為原極大值乘以當前元素。

最應該小心的地方是更新全局最大值:這里的全局最大值不能和極大值比較,而應該和極小值乘以當前元素值比較,即擴展當前subarray的選擇比較。因為如果極大值此時為1,則并不是靠實實在在存在的,以當前元素結尾的subarray獲得,而是靠舍棄當前元素,寄希望于之后“可能”出現的新subarray。舉個例子,如果數組為{-2},或者{-1, 0, -2},那么無論如何是不會出現最大值為1這種情況的,因為負數的后面沒有出現過正數。

3)如果當前元素為0,那么包括一個0會使得極大值成為0,而按照操作規定,這里的極大值應該大于等于1,所以應該舍棄當前元素,新起一個subarray。

對于極大值和極小值,由于新起一個subarray,全部還原為1。

對于全局最大值的更新,這里和2)類似。由于極大值的獲取是寄希望于之后“可能”出現的新subarray,所以更新全局最大值的時候不能和此時的極大值1進行比較,而應該和實實在在的0比較。


以下代碼,loc_min和loc_max表示極小值和極大值,glb_max為所求。

public int maxProduct(int[] A) { int loc_min = 1, loc_max = 1; // Make sure thoese local min/max values are greater than or equal to 1 all the time. int glb_max = A[0]; for (int i : A) { if (i > 0) { glb_max = Math.max(glb_max, loc_max * i); loc_max *= i; loc_min *= i; } else if (i < 0) { glb_max = Math.max(glb_max, loc_min * i); int temp = loc_max; loc_max = Math.max(loc_min * i, 1); loc_min = temp * i; } else { // i == 0. glb_max = Math.max(glb_max, 0); loc_max = 1; loc_min = 1; } } return glb_max; }


思路二:如果數組里面沒有0,這題可以得到大大簡化,所以我們可以先考慮如何處理一個不含0的數組。如此一來,不管怎么乘,絕對值都會增長,所以最重要的就是要保證最后的乘積為正數。因此,可以分為兩種情況討論:

1)如果數組內負數的個數為偶數,直接包括整個數組即可,最大乘積就是整個數組元素的乘積。

2)如果數組內負數的個數為奇數,則應該丟棄一個含有一個奇數的部分。為了使得所剩的數組最大限度的連續,無非就是兩種情況:

2.1) 丟棄掉數組里出現的第一個負數和在它之前的元素。例如{1, 2, -3, 4, -5, 6, 7},由于第一個負數為-3,丟棄最開始的1,2和-3。

2.2) 丟棄掉數組里出現的最后一個負數和在它之后的元素。用上個例子,由于最后一個負數為-5,丟棄最后的-5,6和7。


現在有了對這個題目簡化版的解法,如果擴展到這題的解法呢?很簡單,首先掃一遍數組,以0為邊界,將整個數組分為若干個不含0的subarray,對于每個subarray逐一求解,并求得它們的最大值。另外,由于每個subarray的最大值可能都是負數,所以一旦有0出現,還應該和0比較。代碼如下,start表示subarray的起始下標,為-1的時候表示正在尋找下一個subarray。

public int maxProduct(int[] A) { int start = -1; int max = Integer.MIN_VALUE; for (int i = 0; i < A.length; ++i) { if (start == -1) { if (A[i] != 0) { start = i; } if (i == A.length - 1) { max = Math.max(max, A[i]); } } else { if (A[i] == 0) { max = Math.max(max, maxProductNonZero(A, start, i - 1)); max = Math.max(max, 0); start = -1; } else if (i == A.length - 1) { max = Math.max(max, maxProductNonZero(A, start, i)); start = -1; } } } return max; } private int maxProductNonZero(int[] A, int start, int end) { if (start == end) return A[start]; int count_negs = 0; int product = 1; for (int i = start; i <= end; ++i) { if (A[i] < 0) { count_negs++; } product *= A[i]; } if (count_negs % 2 == 0) { return product; } else { int productBeforeFirstNeg = 1; for (int i = start; i <= end; ++i) { productBeforeFirstNeg *= A[i]; if (A[i] < 0) { break; } } int productAfterLastNeg = 1; for (int i = end; i >= start; --i) { productAfterLastNeg *= A[i]; if (A[i] < 0) { break; } } product = Math.max(product / productBeforeFirstNeg, product / productAfterLastNeg); } return Math.max(product, 0); }

這種解法比較繁瑣,而且由于為了思路清晰,這里我對數組進行了多次掃描,其實可以將循環合并。不過無所謂了,O(n)的時間復雜度不會因為多掃了一兩遍而變化。


比較這兩種解法,第一種適用性更廣,其實對浮點數也同樣適用,而第二種則不能允許有0-1之間的小數。



生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲图片自拍偷拍 | 成人欧美在线 | 国产精品国产三级国产爱网 | 国内精品视频免费观看 | 欧美在线看片 | 91视频综合 | 真实国产乱人伦在线视频播放 | 国产欧美日韩亚洲精品区2345 | 欧美不卡一区二区三区免 | 国产成人无精品久久久 | 成人欧美一区二区三区在线观看 | 国产乱小说 | 久久国产亚洲欧美日韩精品 | 欧美亚洲日本一区 | 在线播放人成午夜免费视频 | 亚洲网站在线免费观看 | 久久久亚洲欧洲日产国码606 | 亚洲高清中文字幕一区二区三区 | 在线观看免费精品国自产 | 久久中文字幕综合不卡一二区 | 成人欧美一区二区三区黑人免费 | 手机看片欧美 | 秋霞伊人网 | 亚洲国产高清视频在线观看 | 久久综合精品国产一区二区三区无 | 久久精品免视国产 | 亚洲区精品久久一区二区三区 | 久久久男人天堂 | 日本午夜片成年www 日本午夜三级 | 国产高清在线精品二区一 | 成人精品一区二区不卡视频 | 国产欧美另类 | 亚洲成年人在线 | 黑人和黑人激情一级毛片 | 欧美亚洲综合在线观看 | 日韩欧美专区 | 一区二区三区在线观看视频 | 欧美视频自拍偷拍 | 久久精品国产亚洲a不卡 | 羞羞网站在线观看 | 欧美特级一级毛片 |