JAVA 三數之和

2021-08-28 04:16:40 字數 4299 閱讀 9942

給定乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。

注意:答案中不可以包含重複的三元組。

例如, 給定陣列 nums =[-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合為:

[ [-1, 0, 1],

[-1, -1, 2]

]

解題思路

我們首先想到的解法是通過三重迴圈,於是我就寫出了如下**:

class

solution:

defthreesum

(self, nums):

""" :type nums: list[int]

:rtype: list[list[int]]

"""result =

for i, a in enumerate(nums):

for j, b in enumerate(nums[i + 1:]):

for _, c in enumerate(nums[j + i + 2:]):

if a + b + c == 0:

return result

但是上面這個**是有問題的,因為我們沒有考慮結果重複的問題。接著我們想到可以通過collections.counter記錄所有數字出現的次數,如果前後有相同的話,我們就不新增到result中去。於是就有了下面的寫法

class

solution:

defthreesum

(self, nums):

""" :type nums: list[int]

:rtype: list[list[int]]

"""from collections import counter

k =

result =

for i, a in enumerate(nums):

for j, b in enumerate(nums[i + 1:]):

for _, c in enumerate(nums[j + i + 2:]):

if a + b + c == 0

and counter([a, b, c]) not

in k:

for i in k:

return result

但是這種寫法的缺點很明顯,演算法的時間複雜度是o(n^3)這個級別的。我們能不能優化到o(n^2)這個級別呢?我們可以參考leetcode 1:兩數之和(最詳細解決方案!!!)文中的方法,通過乙個hash表來記錄nums中所有元素出現的次數。

class

solution:

defthreesum

(self, nums):

""" :type nums: list[int]

:rtype: list[list[int]]

"""nums_hash = {}

result = list()

for num in nums:

nums_hash[num] = nums_hash.get(num, 0) + 1if0

in nums_hash and nums_hash[0] >= 3:

nums = sorted(list(nums_hash.keys()))

for i, num in enumerate(nums):

for j in nums[i+1:]:

if num*2 + j == 0

and nums_hash[num] >= 2:

if j*2 + num == 0

and nums_hash[j] >= 2:

dif = 0 - num - j

if dif > j and dif in nums_hash:

return result

當然這個演算法還有優化的空間,我們知道三個數和為0,那麼在三個數不全為0的情況下,必然有乙個正數和乙個負數,那麼我們可以通過兩個list去訪問nums中含有不重複元素的正數和負數。那樣我們就不用o(n^2)(n=len(nums))的時間,而只需要o(n*m)(n+m=len(nums))的時間複雜度。

另外我們還知道乙個條件,對於a,b,c三個數,如果a是正數,b是負數,那麼-c一定比b小,或者比a大。

例如:

a =

1b =-2

c =1-c=

-1a =3

b =-

2c =-1

-c=1同時也很好證明

-c= (a + b)即-c

- a = b a>=

0->

-c< b

-c= (a + b)即-c

- b = a b<

0->

-c> a

所以我們可以這樣去解這個問題。

class

solution:

defthreesum

(self, nums):

""" :type nums: list[int]

:rtype: list[list[int]]

"""nums_hash = {}

result = list()

for num in nums:

nums_hash[num] = nums_hash.get(num, 0) + 1if0

in nums_hash and nums_hash[0] >= 3:

neg = list(filter(lambda x: x < 0, nums_hash))

pos = list(filter(lambda x: x>= 0, nums_hash))

for i in neg:

for j in pos:

dif = 0 - i - j

if dif in nums_hash:

if dif in (i, j) and nums_hash[dif] >= 2:

if dif < i or dif > j:

return result

此處應有掌聲,非常好的解法是不是o(∩_∩)o

另外這個問題我們也可以使用leetcode 167:兩數之和 ii - 輸入有序陣列(最詳細解決方案!!!)這篇文章中提到的對撞指標的思路。我們首先要將nums排序。

-4 -1 -101

2i l r

l = i+1

我們實際上只要考慮nums[i] <= 0的部分,因為當nums[i] > 0時,必然會造成nums[i], nums[l], nums[r]全部》0,這顯然不對。當i > 0時,我們要考慮nums[i - 1] == nums[i],如果成立,我們要跳出本次迴圈,執行++i,直到不成立為止。

所以我們就有了如下的做法

class

solution:

defthreesum

(self, nums):

""" :type nums: list[int]

:rtype: list[list[int]]

"""result = list()

nums_len = len(nums)

if nums_len < 3:

return result

l, r, dif = 0, 0, 0

nums.sort()

for i in range(nums_len - 2):

if nums[i] > 0:

break

if i > 0

and nums[i - 1] == nums[i]:

continue

l = i + 1

r = nums_len - 1

dif = -nums[i]

while l < r:

if nums[l] + nums[r] == dif:

while l < r and nums[l] == nums[l + 1]:

l += 1

while l < r and nums[r] == nums[r - 1]:

r -= 1

l += 1

r -= 1

elif nums[l] + nums[r] < dif:

l += 1

else:

r -= 1

return result

兩數之和,三數之和

兩數之和 方法一 暴力 throw new illegalargumentexception 時間複雜度 o n 2 空間複雜度 o 1 public int twosum int nums,int target throw newillegalargumentexception no twosum...

兩數之和 三數之和 四數之和

兩數之和意思就是 給你乙個陣列,從中找出兩個數字,讓他們的和等於乙個具體的target。找到所有這樣的兩個數。並且這兩個數字不能完全一樣。n數之和的意思是 給你乙個陣列,從中找出n個數字,讓他們的和等於乙個具體的target。找到所有這樣的n個數。並且這n個數字不能完全一樣。最基礎的,也是最關鍵的就...

兩數之和,三數之和,最接近的三數之和,四數之和

二數之和 給定乙個整數陣列nums和乙個目標值target,請你在該陣列中找出和為目標值的那兩個整數,並返回他們的陣列下標。你可以假設每種輸入只會對應乙個答案。但是,你不能重複利用這個陣列中同樣的元素。示例 給定 nums 2,7,11,15 target 9 因為 nums 0 nums 1 2 ...