原題地址:http://oj.leetcode.com/problems/4sum/
題意:從數組中找到4個數,使它們的和為target。要求去重,可能有多組解,需要都找出來。
解題思路:一開始想要像3Sum那樣去解題,時間復雜度為O(N^3),可無論怎么寫都是Time Limited Exceeded。而同樣的算法使用C++是可以通過的。說明Python的執行速度比C++慢很多。還說明了一點,大概出題人的意思不是要讓我們去像3Sum那樣去解題,否則這道題就出的沒有意義了。這里參考了kitt的解法:http://chaoren.is-programmer.com/posts/45308.html
需要用到哈希表的思路,這樣可以空間換時間,以增加空間復雜度的代價來降低時間復雜度。首先建立一個字典dict,字典的key值為數組中每兩個元素的和,每個key對應的value為這兩個元素的下標組成的元組,元組不一定是唯一的。如對於num=[1,2,3,2]來說,dict={3:[(0,1),(0,3)], 4:[(0,2),(1,3)], 5:[(1,2),(2,3)]}。這樣就可以檢查target-key這個值在不在dict的key值中,如果target-key在dict中並且下標符合要求,那么就找到了這樣的一組解。由於需要去重,這里選用set()類型的數據結構,即無序無重復元素集。最后將每個找出來的解(set()類型)轉換成list類型輸出即可。
代碼:
class Solution: # @return a list of lists of length 4, [[val1,val2,val3,val4]] def fourSum(self, num, target): numLen, res, dict = len(num), set(), {} if numLen < 4: return [] num.sort() for p in range(numLen): for q in range(p+1, numLen): if num[p]+num[q] not in dict: dict[num[p]+num[q]] = [(p,q)] else: dict[num[p]+num[q]].append((p,q)) for i in range(numLen): for j in range(i+1, numLen-2): T = target-num[i]-num[j] if T in dict: for k in dict[T]: if k[0] > j: res.add((num[i],num[j],num[k[0]],num[k[1]])) return [list(i) for i in res]
再貼兩個過不了的O(N^3)寫法。
一:
class Solution: # @return a list of lists of length 4, [[val1,val2,val3,val4]] def fourSum(self, num, target): num.sort(); res=[] for i in range(len(num)): if i>0 and num[i]==num[i-1]: continue for j in range(i+1,len(num)): if j>i+1 and num[j]==num[j-1]: continue l=j+1; r=len(num)-1 while l<r: sum=num[i]+num[j]+num[l]+num[r] if sum>target: r-=1 elif sum<target: l+=1 elif l>j+1 and num[l]==num[l-1]: l+=1 elif r<len(num)-1 and num[r]==num[r+1]: r-=1 else: res.append([num[i],num[j],num[l],num[r]]) l+=1; r-=1 return res
二:
class Solution: # @return a list of lists of length 4, [[val1,val2,val3,val4]] def fourSum(self, num, target): num.sort(); res=[] for i in range(len(num)-3): if i==0 or num[i]>num[i-1]: for j in range(i+1,len(num)-2): if j==i+1 or num[j]>num[j-1]: left=j+1; right=len(num)-1 while left<right: if num[i]+num[j]+num[left]+num[right]==target: res.append([num[i],num[j],num[left],num[right]]) left+=1; right-=1 while left<right and num[left]==num[left-1]: left+=1 while left<right and num[right]==num[right+1]: right-=1 elif num[i]+num[j]+num[left]+num[right]>target: while left<right: right-=1 if num[right]<num[right+1]: break else: while left<right: left+=1 if num[left]>num[left-1]: break return res