2.18
陣列分割
為了減少遍歷次數,可以先對陣列排序。再將所有可能的組合大致分成幾組,每個組的陣列和也是公升序的,通過不斷的分組、查詢,確定上下邊界條件,最終找到所求子陣列。
如果陣列各個元素均不相同,可以採用下面的演算法:
先將陣列
排序,並計算出各元素的總和的一半
s(=sum/2.0)
,(對陣列的劃分時,可以先選中
a0 ,再取
n-1個數)。 假設
ti =sum(a0 +ai +an+2 +an+3 …+a2n-1 ) (0則陣列
也是公升序。如果
tn+1
<=s
則tn+1
即為所求,如果存在
ti =s
,則ti
即為所求。否則,可以通過二分法找到唯一的i、
j使得tij
,(選中
a0 和
aj ),記錄
ti ,假設
ri =sum(a0 +aj +ai +an+3 +an+4 …+a2n-1 ) (j,則
tj =rn+2
,比較ti 、
rj+1
、rn+2
,再對ri 進行類似
ti 的分析,找出下乙個數。通過不斷的分組和查詢和判斷,最終可以找到所求的
n個數。
例如:長度為
8的陣列:共有
35種組合,對每種組合的子陣列和,可以劃分到幾個區間:
(下面的
0123
表示取a0 +a1 +a2 +a3 )
較小值較大值
0123
——0167
(共15個)
0234
——0267
(共10個)
0345
——0367 (共6
個) 0456
——0467 (共3
個) 0567
——0567 (共1
個) (各個較大值不必計算,它們間必然只有乙個數不同(並且這個不同的數在公升序數列中的位置是連續的),查詢
s在哪兩個較大值之間,可以用
s減去相同的數的和,得到的差去指定的範圍(不同的那個數的位置範圍)進行二分查詢。)
由於陣列是公升序,陣列元素各不相同,右邊的「較大值」都是公升序排列且不會重複。利用陣列和的一半
s進行查詢,如果s在
0267
和0367
之間。只要記錄
0267
,並在適當時候判斷該記錄是否是所求的,展開
0345
——0367的6
個數,
0345
——0347(共3
個) 0356
——0357(共2
個) 0367
——0367(共1
個) 再重複上述操作。
讀書筆記之程式設計之美 2 18 陣列分割
拿到這個題目,首先想到的也是先計算sum 2,然後從2n個陣列找出n個值的和正好為sum 2即可,但是有可能構造不出正好和為sum 2的情況。解法一就不說了,不是正確的解法。解法二看似是動態規劃,但是只計算出了可能的sum值,好像還是找不到是哪幾個值排列組合出來的。另外,也不知道那個o 2 n 是怎...
《程式設計之美》 2 18 陣列分割
題目概述 有乙個沒有排序,元素個數為2n的正整數陣列。要求把它分割為元素個數為n的兩個陣列,並使兩個子陣列的和最接近。假設陣列a 1.2n 所有元素的和是sum。模仿動態規劃解0 1揹包問題的策略,令s k,i 表示前k個元素中任意i個元素的和的集合。顯然 s k,1 s k,k s k,i s k...
程式設計之美 2 18 陣列分割
本人第一次寫部落格,如有不對,請多加指正。解法一的思路很明顯是錯的。貪心演算法很多情況下求不出最佳解答,因為可能兩個陣列間需要同時交換兩個或者兩個以上的數,才能實現差值最小。如 解法二的思路將也就是乙個組合的問題在2n個陣列中找出n個數,使得n個數之和最接近於sum 2,這裡取小於等於sum 2的情...