三数之和
给你一个包含 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 {
func threeSum(_ nums: [Int]) -> [[Int]] {
// 异常情况
if nums.count < 3 { return [] }
let sortedNums = nums.sorted()
var result = Set<[Int]>()
// 顺序的数组中固定一个数字,然后在固定数字右边的数组中从最左和最右向中间遍历,找到和为零的方案。
for (index, number_first) in sortedNums.enumerated() {
var l = index + 1, r = sortedNums.count - 1
// 第一个数字大于零后续也会大于零
if number_first > 0 { break }
while l < r {
let sum = number_first + sortedNums[l] + sortedNums[r]
if sum == 0 {
result.insert([number_first, sortedNums[l], sortedNums[r]])
// 找到满足条件的数字,然后还需要继续寻找其他和为零可能的方案,所以需要继续向中间寻找
l += 1
r -= 1
}else if sum > 0 {
// 类似二分法,和大于零,最右面往左移
r -= 1
}else if sum < 0 {
// 类似二分法,和小于零,最左面往右移
l += 1
}
}
}
return result.map { $0 }
}
}
方案二
思路基本同方案一, 但代码更精简, 耗时也更少
解题思路:
- 1.先排序,减少多余操作,从小到大排序
- 2.重复过滤
- 3.将三数之和为0转换为 a+b = -c,转成两个数之和
- 4.通过下标i、下标low = i + 1、下标high = nums.count - 1来判断相等 target = 0 - nums[i]
- 5.若nums[low] + nums[high] = target 则加入结果集同时i右移、high左移继续遍历,若 < target ,则右移, 若 > target 则左移
class Solution {
func threeSum(_ nums: [Int]) -> [[Int]] {
guard nums.count > 2 else {
return []
}
var results = [[Int]]()
let sortedNums = nums.sorted()
for i in 0..<sortedNums.count-1 {
if i > 0 && sortedNums[i] == sortedNums[i-1] {
continue
}
let target = 0 - sortedNums[i]
var low = i + 1
var high = nums.count - 1
while low < high {
let sum = sortedNums[low] + sortedNums[high]
if sum == target {
let result = [sortedNums[i], sortedNums[low], sortedNums[high]]
results.append(result)
while (low < high && sortedNums[low] == sortedNums[low+1]) {
low += 1
}
while (low < high && sortedNums[high] == sortedNums[high-1]) {
high -= 1
}
low += 1
high -= 1
} else if sum < target {
low += 1
} else {
high -= 1
}
}
}
return results
}
}