分类->leetcode->中等题
题目 LeetCode 热题100-> 15. 三数之和
https://leetcode.cn/problems/3sum/description
这是双指针算法中的典型例题,也是面试中经常出现的题,下面我将以LeetCode 热题100中的 15. 三数之和为例,通过图解详细步骤的方式讲解这类问题应该怎么做。
题目介绍
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
解题思路
题目有几个关键字“数组”、“满足...”、“不重复”,将选择限定在了数组,并且要选三个数满足一定条件,那么我们应该想到使用双指针解题,在计算的时候需要注意题目中要求避免重复。下面开始细说该怎么解题。
在小学一年级的时候,大家都学过三个数的加减法,其精髓就在于将其拆分成两个数的加减法,a+b+c=a+(b+c),这道题也是,我们首先需要将三数之和变为两数之和。既然是求和,还要避免重复,那么首先需要做的就是数组排序。
当数组变成非递减的有序数组后,我们先选一个数作为“a”,即将三数之和变为两数之和的关键,用 i 指向该数,这里从数组的起始位置开始,即 0 序号开始,并以数组长度-3的序号为终止点(当 i =nums.length-3时,是最后一个组合),将0-nums[i]作为两数之和应该满足的要求。
剩下需要解决的问题就是寻找之和为0-nums[i]的两个数,这很容易就想到双指针,那双指针的起点是什么呢?这里将 l 作为指向两数中偏小的数的指针,即左指针,起始位置定为 i +1;将 r 作为指向两数中偏大的数的指针,即右指针,起始位置指向数组末端。当nums[l]+nums[r]<0-nums[i]时,l 左移,寻找两数之和更大的组合;当nums[l]+nums[r]>0-nums[i]时,r 右移,寻找两数之和更小的组合,直至 l 和 r重叠,遍历结束。
需要注意的是,由于题目要求避免重复,所以在三个指针 i、l、j 移动的时候都需要避免重复,跳开重复元素。
为了更好地演示具体步骤,我根据题目中的示例 [-1,0,1,2,-1,-4] 绘制了步骤图解,如下所示:
参考代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> a = new ArrayList();
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2; i++) {
if (nums[i] > 0) {
return a;
}
if (i > 0 && nums[i - 1] == nums[i]) {
continue;sanshu
}
int sum = 0 - nums[i];
int l = i + 1, r = nums.length - 1;
while (l < r) {
if (nums[l] + nums[r] == sum) {
a.add(Arrays.asList(nums[i], nums[l], nums[r]));
l++;
r--;
while (l < r) {
if (nums[l] == nums[l - 1]) {
l++;
} else {
break;
}
}
while (l < r) {
if (nums[r] == nums[r + 1]) {
r--;
} else {
break;
}
}
} else if (nums[l] + nums[r] < sum) {
l++;
} else {
r--;
}
}
}
return a;
}
}
最近正在学习算法和刷 leetcode,发现图解的方式更能加深印象,就记录了下来。
不过一个人学感觉没有什么动力,有些题也想不太明白,创建了一个算法交流群,如果有同在刷题的小伙伴,欢迎加入~
qq群号:643418253