LeetCode15.ThreeSum

题目

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]

输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []

输出:[]

示例 3:

输入:nums = [0]

输出:[]

提示:

0 <= nums.length <= 3000

-105 <= nums[i] <= 105

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

1. 暴力破解

三重循环,时间复杂度O(n^3)

2. 双重循环 + map

两重循环
第三重循环直接去map中查找
时间复杂度 O(n^2)

3. 排序 + 双指针

先将数组元素进行排序(便于跳过重复元素,如果当前元素和前一个元素相同则跳过)
从第一个元素进行循环
设置两个指针(左右指针向内收缩):
    左指针 = 循环元素后第一个元素
    右指针 = 数组最后一个元素
如果循环元素 + 左指针元素 + 右指针元素:
    大于0:
        右指针向左移动一位(因为结果大于0,而数组已经是有序的,所以要减小大的值)
    小于0:
        左指针向右移动一位
    两指针相遇:
        结束,不存在
优化:如果循环的元素大于0,则排序后的数组另外两个数肯定也大于0,sum不可能等于0,所以直接break    

https://leetcode-cn.com/problems/3sum/solution/zhi-zhen-yi-dong-guo-cheng-zhong-tiao-guo-zhong-fu/

代码

// 排序 + 双指针
func threeSum(nums []int) [][]int {
// 对元素进行排序
sort.Ints(nums)
// 返回结果
result := [][]int{}
// 循环长度-2次,因为最后左右两个指针元素可以不用循环
for i := 0;i < len(nums)-2;i++ {
	n1 :=nums[i]
	// 如果当前元素已经大于0,直接跳出循环
	if n1 > 0{
		break
	}
	// 如果与上一个元素相同跳过
	if i > 0 && n1 == nums[i - 1] {
		continue
	}
	// 左右两个指针
	l,r := i+1,len(nums)-1
	for l < r{
		n2,n3 := nums[l],nums[r]
		// 如果三数之和等于0,保存结果并跳过重复元素
		if n1 + n2 + n3 == 0{
			result = append(result,[]int{n1,n2,n3})
			for l < r && nums[l] == n2{
				l++
			}
			for l < r && nums[r] == n3{
				r--
			}
			// 小于0说明元素太小了,左指针向大的元素方向移动
		}else if n1 + n2 + n3 < 0{
			l++
		}else{
			r--
		}
	}
}
return result
}

// map加速查询
func threeSum2(nums []int) [][]int {
	// 对数组进行排序
	sort.Ints(nums)
	// 存储nums元素数量
	var dataCountMap = make(map[int]int)
	// 将nums数组中的元素添加到map中
	for _,v := range nums {
		// 已经存在数量置为1,否则++
		if _,ok:= dataCountMap[v];!ok{
			dataCountMap[v] = 1
		}else{
			dataCountMap[v]++
		}
	}
	// 用于存储结果,达到去重作用
	var solutionMap = make(map[[2]int]struct{})
	for i := 0;i < len(nums) - 2;i++{
		for j := i+1;j < len(nums)-1;j++{
			// a+b+c = 0 c = -a-b
			expected := -nums[i] - nums[j]
			// 判断map中是否存在符合的元素,且元素要大于等于j索引上的元素,因为开始已经将数组排序了
			if num,ok := dataCountMap[expected];ok && expected >= nums[j]{
				// 如果和i或j索引元素一样将num局部变量--,作用是判断是否有足够数量的元素可供使用,不能使用同一个重复元素
				if expected == nums[i]{
					num--
				}
				if expected == nums[j]{
					num--
				}
				if num > 0 {
					solutionMap[[2]int{nums[i],nums[j]}] = struct{}{}
				}
			}
		}
	}
	var result = make([][]int,len(solutionMap))
	i := 0
	for k := range solutionMap{
		result[i] = []int{k[0],k[1],-k[0]-k[1]}
		i++
	}
	return result
}
原文地址:https://www.cnblogs.com/hzpeng/p/15033147.html