三數之和(3 Sum)
題幹:
給你一個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例:
給定陣列 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合為:
[
[-1, 0, 1],
[-1, -1, 2]
]
來源:力扣
思路與 讓我們一起啃演算法—-兩數之和 相似,求 兩數之和 時我們引入了一個偏移指標,這題需要引入 三個 偏移指標。
解題思路
首先我們對 nums 進行排序,接著初始化: a 指向 nums 陣列的第一個元素,b 指向 nums[a] 的後一個元素,c 指向 nums 的最後一個元素。
初始化時,b 始終指向 nums[a] 的後一個元素, c 始終指向 nums 的最後一個元素。
題目要求三數之和為 0,即 nums[b] + nums[c] = 0 - nums[a],我們將 0 - nums[a] 記為 sum。
當 nums[b] + nums[c] 大於 sum 時,c 向左移動;當 nums[b] + nums[c] 小於 sum 時,b 向右移動;當 nums[b] + nums[c] 等於 sum 時,這時候 nums[a], nums[b], nums[c] 為一組有效值,記錄下來,b 向右移動,c 向左移動。直到 b 大於等於 c 時,移動 a 指標再重新初始化 b 和 c,重複上面的步驟,直到 a 越界。
a 越界條件: a 大於 nums 陣列倒數第三個索引時即越界。因為我們有三個指標,當 a 為陣列倒數第三個索引時,b為倒數第二個索引,c為倒數第一個索引。
這裡有一個注意點: a,b,c 指標在移動的過程中需要與前一次指向的陣列值對比,如果相等需要繼續移動,直到不相等。例如 nums[b] 為 1,b 向右移動一位,即 b++, 這時候發現 nums[b] 仍為 1,b 需要繼續向右移動一位,直到 nums[b] 不為 1。
上面的操作是為了保證結果中沒有重複的元組。
例如 nums 為 [-1 -1 0 1 2],假設 a 為 0,即 nums[a] 為 -1,會找到一個有效元組 [-1, 0, 1],這時候向右移動 a ,即 a 為 1,nums[a] 為 -1 與上一次值相同,a 需要繼續向右移動,否則又會找到一個有效元組 [-1, 0, 1],這就重複了。同理 b,c 也是如此。
流程圖如下:
程式碼實現
GO語言實現
func threeSum(nums []int) [][]int {
var result [][]int
if len(nums) <= 2 {
return result
}
// 需要排序
sort.Ints(nums)
a := 0
// 有三個指標,a 是最左邊的,所以 a 最大值為 nums 倒數第三個索引
for a <= len(nums)- 3 {
// 保證 a 在向右移動時指向的值,不與之前的值相等
if a != 0 && nums[a] == nums[a-1] {
a++
continue
}
// b 為 a 的後一個指標
b := a + 1
// c 指向 nums 最後一個元素
c := len(nums) -1
// sum 的值為後續 nums[b] + nums[c] 的值
sum := 0 - nums[a]
// b 必須小於 c
for b < c {
// 保證 c 在向左偏移時指向的值,不與之前的相等
if c < len(nums) - 1 && nums[c] == nums[c + 1] {
c--
continue
}
// 保證 b 在向右偏移時指向的值,不與之前的相等
if b > a + 1 && nums[b] == nums[b-1] {
b++
continue
}
// 比較和
if nums[b]+nums[c] > sum {
c--
} else if nums[b]+nums[c] < sum {
b++
} else {
result = append(result, []int{nums[a], nums[b], nums[c]})
c--
b++
}
}
// a 向右移動
a++
}
return result
}
總結
每天進步一點點,加油!
演算法教程專案,每天更新一題,點個 star 支援一下呀:
github.com/wx-satellite/learning-a...
本作品採用《CC 協議》,轉載必須註明作者和本文連結