給定乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
例如, 給定陣列 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合為:
[
[-1, 0, 1],
[-1, -1, 2]
]
1、三重迴圈
雙重迴圈行不通,其實從組合數量出發,因為組合個數是n
3n^3
n3這個數量級,要遍歷所有的組合,時間複雜度應該也在o(n
3)o(n^3)
o(n3
)的樣子,使用三重迴圈應該是最佳的方法:
(1)第一重迴圈:left(取值範圍:0−n
−30-n-3
0−n−3)
(2)第二重迴圈:middle(取值範圍:1−n
−21-n-2
1−n−2)
(3)第三重迴圈:right(取值範圍:2−n
−12-n-1
2−n−1)
2、排序之後
等等,之前的結論都是建立在陣列是無序的情況下,事實上,對陣列排序的時間複雜度也僅僅是o(n
logn
)o(nlogn)
o(nlog
n),如果使用排序後的陣列能否大幅減少查詢時間呢?
每次將三個數之和(sum
=lef
t+mi
ddle
+rig
htsum=left+middle+right
sum=le
ft+m
iddl
e+ri
ght)與0比較:
(1)比0大則移動middle或者left
(2)比0小則移動middle或者right
(3)等於0,則儲存下來,然後???
這個方法也有很多問題,每次的移動,有兩個選擇,但是這兩個選擇並不是等價的
比如說當:
s um
>
0sum>0
sum>
0時,移動middle好呢還是移動right好?
還有當出現0的時候,為了尋找下乙個零,該怎麼移動?
3、分而治之
聯想之前兩數之和,三數之和的問題能否轉為兩數之和呢?
答案是肯定的。假設三個數為:i,j,k。對於兩數之和的target,這裡要求:target=-i
然後遍歷整個陣列,時間複雜度應該是:o(n
2)o(n^2)
o(n2
)最終我採用了這個方案,但是還是有些問題:
(1)因為陣列中可能存在重複的數,此時會有兩個一樣的target,返回的vector也是一樣的
(2)多對多的問題:
例如:i+j+k=0
對i來說,還有:
i+j1+k1=0
i+j2+k2=0
…i+jn+kn=0
對j來說,還有:
i1+j+k1=0
i2+j+k2=0
…in+j+kn=0
同理,k也有這種可能
但是之前的兩數之和的程式是假定,只有乙個解
1、嘗試-集合去重
接下來給出解決上述問題的方案:
(1)使用set來儲存陣列中的數,這樣可以達到去重的目的
(2)使用set來儲存得到的向量,且必須保持向量中的相對位置不變,這樣也可以去除重複的向量
很遺憾,這個想法是錯誤的,比如:[-1,0,1,-1]
第一次將[-1,0,1]放入集合,第二次還是會將[0,1,-1]也放進集合裡面
再比如:[-1,0,1,-1,0]這樣的資料
第一次將-1所在的所有向量選出來時,就已經重複了:
[-1,0,1]
[-1,1,0]
因此,集合沒有辦法對向量去重
實際上去重失敗的原因是:無法通過相對位置來決定唯一向量。所以,只要事先進行排序,就能解決這個問題:
c++**:
class solution
};
執行效率:
港真,我都不想上圖了
更讓我震驚的是使用記憶體
短短50行的**用了600多mb的記憶體,這是咋回事???????
更新:這麼慢應該不是雜湊表的問題,我覺得是因為不必要的操作太多了,而且使用這種方法找兩數之和,不如雙指標來的快,實際上這個**已經是顯式的三重迴圈了
主要的思想還是分而治之,但是在解決兩數之和的問題時,不採用雜湊表,使用雙指標,看看速度能否更快一點
c++**:
class solution
if (nums[n] + nums[i] + nums[j] < 0)
if (nums[n] + nums[i] + nums[j] == 0) }}
} return nums_vector;
}};
執行效率:
比之前的版本強了很多,但是還是比較慢
記憶體占用:
可見,還是佔了很大一部分的記憶體
仔細看看這段**,會發現很多地方寫的很冗餘
(1)冗餘1
if (nums_p1.count(nums[n]) == 0)
修改為:
if (n > 0 && nums[n] == nums[n - 1])
使用set判定重複,實際由於已經排好序了,因此判定重複只用與前乙個元素比較即可
(2)冗餘2
對向量的重複操作,總是在不斷插入刪除
c++**:
class solution
if (nums[i] + nums[j] < target)
if ( nums[i] + nums[j] == target) );
while (i + 1 < j && nums[i] == nums[i + 1])
i++;
while (j - 1 > i && nums[j] == nums[j - 1])
j--;
i++;}}
} return vector>(nums_vector.begin(), nums_vector.end());
}};
效率還是老樣子,沒什麼提公升。。。。。。。
看了排名靠前的幾個,思路差不多,不知道為啥那麼快
LeetCode 15 三數之和
15.給定乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組 方法一,個人解法正確,但是效率太低,時間複雜度o n 3 時間超時,無法提交至leetcode public s...
leetcode 15 三數之和
給定乙個包含 n 個整數的陣列nums,判斷nums中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。例如,給定陣列 nums 1,0,1,2,1,4 滿足要求的三元組集合為 1,0,1 1,1,2 class solutio...
leetcode15 三數之和
給定乙個包含 n 個整數的陣列nums,判斷nums中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。例如,給定陣列 nums 1,0,1,2,1,4 滿足要求的三元組集合為 1,0,1 1,1,2 先找兩數之和,然後再用un...