每日刷題 15 三數之和(雙指標)

2021-10-07 04:02:09 字數 3456 閱讀 8614

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

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

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

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

[[-1, 0, 1],

[-1, -1, 2]

]

題目鏈結

本題與兩數之和類似,但是做法不盡相同。

題目中要求找到所有不重複且和為 0的三元組,這個不重複的要求使得我們無法簡單地使用三重迴圈列舉所有的三元組。這是因為在最壞的情況下,陣列中的元素全部為0,即

[0, 0, 0, 0, 0, …, 0, 0, 0]

此時可以看到任意乙個三元組之和都為0,時間複雜度為o(n^3)。

為達到不重複的要求,我們需要保證:

第二重迴圈列舉的元素不小於第一重迴圈列舉的元素。

第三重迴圈列舉的元素不小於第二重迴圈列舉的元素。

由此,我們很容易得到基本的解題思路。

我們可以將陣列中的元素從小到大進行排序,隨後使用普通的三重迴圈就可以滿足上面的要求。

同時,對於每一重迴圈而言,相鄰兩次列舉的元素不能相同,否則也會造成重複。舉個例子,如果排完序的陣列為

[0, 1, 2, 2, 2, 3]

我們使用三重迴圈列舉到的第乙個三元組為 (0,1,2),如果第三重迴圈繼續列舉下乙個元素,那麼仍然是三元組 (0,1,2),產生了重複。因此我們需要將第三重迴圈「跳到」下乙個不相同的元素,即陣列中的最後乙個元素 3,列舉三元組 (0,1,3)。對於第一重和第二重迴圈也做同樣的去重處理(實際就是直接跳過)。

偽**如下:

nums.sort()

for first = 0 .. n-1

// 只有和上一次列舉的元素不相同,我們才會進行列舉

if first == 0 or nums[first] != nums[first-1] then

for second = first+1 .. n-1

if second == first+1 or nums[second] != nums[second-1] then

for third = second+1 .. n-1

if third == second+1 or nums[third] != nums[third-1] then

// 判斷是否有 a+b+c==0

check(first, second, third)

通過上面的分析我們可以看出,時間複雜度依然是o(n^3)。通過分析,如果我們固定了前兩重迴圈列舉到的元素 a 和 b,那麼只有唯一的 c 滿足 a+b+c=0。當第二重迴圈往後列舉乙個元素 b′時,由於 b′>b,那麼滿足 a+b′+c′=0的 c′一定有 c′ 0

third = third-1

// 判斷是否有 a+b+c==0

check(first, second, third)左指標b每次會向右移動乙個位置,而右指標c會向左移動若干個位置。此時時間複雜度降低為o(n^2)。

還應當注意一點:左指標始終應當小於右指標。

觀察上面的偽**我們發現,在第二層迴圈遍歷左指標時,右指標可能會移動若干個位置,導致了迴圈的巢狀。雖然沒有導致時間複雜度的增加,但是**不美觀。

我們重新梳理一遍思路,發現第二重迴圈可以如此判斷:

固定a,當a+b+c < 0時,說明左指標值太小,右移左指標。

當a+b+c > 0時,說明右指標值太大,左移右指標。

當a+b+c = 0時,得到可行解,同時移動左右指標,並進行去重處理(跳過)。

這樣,第二重迴圈可根據a+b+c 和 0 之間的關係進行判斷。(如果依然不是很理解,可以看下本篇演算法的難點這一部分。)

示例的遍歷過程如下圖所示:

在看這道題的官解時我有這樣的乙個疑問(如果沒有這個疑問可以跳過這一部分):

有這樣的陣列:

[a, b, b』, b",……, c", c』, c]

設a+b+c < 0, a+b』+c > 0

若a+b』+c』 < 0, 按照雙指標應當判斷a+b"+c』 和 0 之間的關係。(即右指標不動,左指標右移)

那麼是否需要判斷a+b』+c 和 0 的關係呢?(即左指標不動,右指標右移)

同理,若a+b』+c』 > 0, 按照雙指標應當判斷a+b』+c" 和 0 之間的關係。(即左指標不動,右指標左移)

那麼是否需要判斷a+b+c" 和 0 的關係呢?(即右指標不動,左指標左移)

證明如下:

綜上分析:利用雙指標,只需要從小到大列舉左指標,同時從大到小列舉右指標,不開歷史的倒車

根據改進思路:左指標b每次會向右移動乙個位置,而右指標c會向左移動若干個位置寫出如下**。

class

solution);

left++

; right--

;while

(left < right && nums[left]

== nums[left -1]

) left++

;while

(left < right && nums[right]

== nums[right +1]

) right--;}

}}return ans;}}

;

根據繼續改進思路:第二重迴圈根據 a+b+c 和 0 之間的關係進行判斷。

class

solution);

++left,

--right;

while

(left < right && nums[left]

== nums[left -1]

)++left;

while

(left < right && nums[right]

== nums[right +1]

)--right;}}

}return ans;}}

;

每日刷題 三數之和

給定乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。示例 給定陣列 nums 1,0,1,2,1,4 滿足要求的三元組集合為 1,0,1 1,1,2 方法一 列舉。將所有...

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 solu...

領扣刷題 15 三數之和

題目要求 給定乙個包含 n 個整數的陣列nums,判斷nums中是否存在三個元素 a,b,c 使得 a b c 0 找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。小白第一次寫部落格,希望大佬多多指教。這是一道在領扣上標記為中等的陣列題目,題目的難點在於去除重複的三元組。我們想...