Leetcode15. 三数之和
题目描述
给你一个包含 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
-
如果 蓝色 +left+right>0,说明right大了,right--
-
如果 蓝色 +left+right<0,说明left小了,left++
-
重复情况考量:
- 蓝色和蓝色+1相同,则蓝色直接+2,跳过蓝色+1
- right和right-1相同,则right直接-2,跳过right-1
- left和left+1相同,则left直接+2,跳过left+1
代码实现:
Golang:
参考:
// 补一个 golang 版本的
func threeSum(nums []int) [][]int {
// 先从小到大排序
sort.Ints(nums)
// 接收结果
var res [][]int
// 获取数组长度
length := len(nums)
// 边界处理,数字不足三个直接返回空
if len(nums) < 3 {
return res
}
// 开始循环第一个固定值
for index, value := range nums {
// 如果固定位的值已经大于0,因为已经排好序了,后面的两个指针对应的值也肯定大于0,则和不可能为0,所以返回
if nums[index] > 0 {
return res
}
// 排除值重复的固定位
if index > 0 && nums[index] == nums[index-1] {
continue
}
// 指针初始位置,固定位右边第一个和数组最后一个
l := index + 1
r := length - 1
// 开始移动两个指针
for l < r {
// 判断三个数字之和的三种情况
sum := value + nums[l] + nums[r]
switch {
case sum == 0:
// 将结果加入二元组
res = append(res, []int{nums[index], nums[l], nums[r]})
// 去重,如果l < r且下一个数字一样,则继续挪动
for l < r && nums[l] == nums[l+1] {
l += 1
}
// 同理
for l < r && nums[r] == nums[r-1] {
r -= 1
}
l += 1
r -= 1
case sum > 0:
// 如果和大于 0,那就说明 right 的值太大,需要左移
r -= 1
// 如果和小于 0,那就说明 left 的值太小,需要右移
case sum < 0:
l += 1
}
}
}
return res
}
我的:
package GoProject
import "sort"
func threeSum(nums []int) [][]int {
// 先从小到大排序
less:= func(i,j int) bool {
return nums[i] < nums[j]
}
sort.SliceStable(nums,less)
//存储结果的二维切片
var result [][]int
//
length := len(nums)
if length < 3{
return result
}
//对蓝色部分进行遍历
for index,value :=range nums{
// 如果固定位的值已经大于0,因为已经排好序了,后面的两个指针对应的值也肯定大于0,则和不可能为0,所以返回
if nums[index] > 0{
return result
}
// 排除值重复的固定位
if index > 0 && nums[index] == nums[index-1]{
continue
}
// 每一轮当中指针初始位置,固定位右边第一个和数组最后一个
left := index + 1
right := length - 1
// 开始移动两个指针
for left < right {
// 判断三个数字之和的三种情况
sum := value + nums[left]+ nums[right]
switch {
case sum == 0:
// 将结果加入二元组
result = append(result, []int{nums[index], nums[left], nums[right]})
// 去重,如果l < r且下一个数字一样,则继续挪动
for left < right && nums[left] == nums[left+1]{
left ++
}
for left < right && nums[right] == nums[right-1]{
right --
}
//因为切片已经升序,所以单纯的left++或者right--,绝对不可能为零(因为上面已经排除的重复的情况)
left ++
right --
case sum > 0:
// 如果和大于 0,那就说明 right 的值太大,需要左移
right --
case sum < 0:
// 如果和小于 0,那就说明 left 的值太小,需要右移
left ++
}
}
}
return result
}
func main(){
}
遇到的问题:
-
问题一:
switch case go写法 -
问题二:
-
问题三:
append()方法为切片添加元素
Go语言的内建函数append()可以为切片动态添加元素。 每个切片会指向一个底层数组,这个数组能容纳一定数量的元素。当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。“扩容”操作往往发生在append()函数调用时。
举个例子:
var citySlice []string
// 追加一个元素
citySlice = append(citySlice, "北京")
// 追加多个元素
citySlice = append(citySlice, "上海", "广州", "深圳")
// 追加切片
a := []string{"成都", "重庆"}
citySlice = append(citySlice, a...)
fmt.Println(citySlice) //[北京 上海 广州 深圳 成都 重庆]
123456789
数组的定义:
a := [5]int{1, 2, 3}
切片的定义:
s := []int{1, 2, 3}
所以:
result = append(result, []int{nums[index], nums[left], nums[right]})
slice_t := [nums[index], nums[left], nums[right]]
slice_t实际上就是 [ nums[index], nums[left], nums[right] ]
所以实际上也就是把一个切片作为一个元素放到了另外一个切片的末尾
// 由题得返回的result的类型是一个二维切片,所以result的元素是一维切片,所以,这里的append用法蛮有意思的 func threeSum(nums []int) [][]int {...}