Source: 4 Sum
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
- Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
- The solution set must not contain duplicate quadruplets.
Example :
Given array S = {1 0 -1 0 -2 2}, and target = 0
A solution set is:
(-2, -1, 1, 2)
(-2, 0, 0, 2)
(-1, 0, 0, 1)
Also make sure that the solution set is lexicographically sorted.
Solution[i] < Solution[j] iff Solution[i][0] < Solution[j][0] OR (Solution[i][0] == Solution[j][0] AND ... Solution[i][k] < Solution[j][k])
解題:
- 這題也是非常適合採用暴力解,套入四個迴圈即可完成。但O(n^4)光看就覺得很嚇人,有什麼方法可以降低複雜度加快處理速度呢?
- 因為題目要求組合不應重複,且 a <= b <= c <= d 條件必須成立,故對陣列先執行排序確立大小關係有助於後續篩選及運算進行;
- 再來是根據題目給予之條件
S[i] + S[j] + S[k] + S[l] = T , i < j < k < l
也就是說
T - (S[i] + S[j]) = S[k] + S[l]
依據這層關係,便可以先用兩層迴圈得到 S[i] 跟 S[j] 的組合,此處可以先用hashmap來排除 [S[i], S[j]] 的重複組合。而 [S[k], S[l]] 這個組合要怎麼做才能達到降低複雜度的目的呢?
- 因我們可以依題目條件得知
T - (S[i] + S[j]) - (S[k] + S[l]) = 0
而且陣列已經過適當排序,此時便可採用從兩端最大最小值來進行比較移動:
預設 k = j+1, l = n-1, 在 k < l 的情況下 如 T - (S[i] + S[j]) - (S[k] + S[l]) > 0 表示S[l]值太大(因S[k]已在最左端,不能再更小) 應調整 l 值; 如 T - (S[i] + S[j]) - (S[k] + S[l]) < 0 表示S[k]值太小(因S[l]已在最右端,不能再更大) 應調整 k 值
- 最後則應注意在得到合適的子陣列值後後續應如何推進序列值 k, l 而不造成重複以及無法結束迴圈之狀況。
Code:
from collections import defaultdict
class Solution:
# @param S : list of integers
# @param T : integer
# @return a list of list of integers
def fourSum(self, S, T):
#since condition a<=b<=c<=d must be applied
S.sort()
sumMatch = defaultdict(list)
n, output = len(S), []
for i in range(n-3):
for j in range(i+1, n-2):
#T-(S[i]+S[j]) == S[k]+S[l]
if [S[i], S[j]] in sumMatch[T-S[i]-S[j]]:
continue
sumMatch[T-S[i]-S[j]].append([S[i], S[j]])
target = T-S[i]-S[j]
k, l = j+1, n-1
while k < l:
if target-S[k]-S[l] > 0:
k += 1
elif target-S[k]-S[l] < 0:
l -= 1
else:
output.append([S[i],S[j],S[k],S[l]])
while S[k] == S[k+1] and k+1 < l:
k += 1
while S[l] == S[l-1] and l-1 > k:
l -= 1
k += 1
l -= 1
return output
GitHub: GitHub