leetcode热题100(15) - 三数之和

Question

leetcode.cn/problems/3s...

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

示例 1:

scss 复制代码
输入: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:

ini 复制代码
输入:nums = [0,1,1]
输出:
[]
解释:
唯一可能的三元组和不为 0 。

示例 3:

lua 复制代码
输入:nums = [0,0,0]
输出:
[[0,0,0]]
解释:
唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

Solution

双指针

前面我们讨论过两数之和,当时是利用Map来解决的,但是三数之后以及后面的四数之和需要换种思路去解答。三重循环的暴力解法本文不讨论,时间复杂度达到了O(N^3) ,会出现超时。

题意要求我们找出3个数字之和为0 的3个数字,什么情况下3个数字会为0?

  1. 3个数字全部为0
  2. 3个数字有正数和负数

我们不妨用指针i遍历数字,在每轮循环中nums[i] 是固定的,因此我们需要找出另外的两个数,可以先将三个数相加,和有三种情况:

  1. 和等于0,此时找到了一个解
  2. 和大于0,数字太大了,我们需要将另外两个数大的那个移动一下,让他变小
  3. 和小于0,数字太小了,我们需要将另外两个数小的那个移动一下,让他变大

那么问题来了,如果才能确保两个数中大的移动之后变小或者小的移动之后变大呢?答案是排序,只有对nums排序后,最小的在左边,此时右移一定是变大;最大的在左边,此时左移一定变小。

题目还要求答案中不可以包含重复的3元组,因此排序后如果nums[i]nums[i+1] 相等,则我们需要跳过nums[i+1] ,对于另外两个数也是一样处理。

java 复制代码
class Solution1 {
        
        public List<List<Integer>> threeSum(int[] nums) {
            if (nums.length == 0) {
                return Collections.emptyList();
            }
            var answer = new ArrayList<List<Integer>>();
            Arrays.sort(nums);
            for (int i = 0; i < nums.length; i++) {
                // 当前数字和上一个数字相同,跳过当前数字
                if (i > 0 && nums[i] == nums[i - 1]) {
                    continue;
                }
                int left = i + 1;
                int right = nums.length - 1;
                while (left < right) {
                    int sum = nums[i] + nums[left] + nums[right];
                    if (sum == 0) {
                        answer.add(List.of(nums[i], nums[left], nums[right]));
                        // left右移到不重复的
                        while (left < nums.length - 1 && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        // right左移到不重复的
                        while (right > 0 && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        // 此时left和right停在和当前数字相等的数字上,所以还得移动
                        left++;
                        right--;
                    } else if (sum > 0) { // 和太大,右指针左移
                        right--;
                    } else { // 和太小,左指针右移
                        left++;
                    }
                }
            }
            return answer;
        }
    }

时间复杂度

O(n^2),n是nums长度,我们有一个for循环和2个while(2个while循环一起算,每个元素也只会访问一次),因此时间复杂度是O(n^2)而不是O(n^3)。

空间复杂度

O(1), 答案所占空间一般不计入空间复杂度,本题中我们除了答案只使用了常数项的变量。

相关推荐
练习时长一年1 小时前
LeetCode热题100(二叉树的最大路径和)
算法·leetcode·职场和发展
2401_872418787 小时前
算法入门:数据结构-堆
数据结构·算法
xwz小王子9 小时前
手术机器人登上Science Robotics:2毫米纤细手臂,从3厘米切口完成腰椎神经减压
算法·机器人
黎阳之光9 小时前
视频孪生智护供水生命线:黎阳之光赋能医疗与园区水务高质量升级
运维·物联网·算法·安全·数字孪生
Black蜡笔小新10 小时前
自动化AI算法训练服务器DLTM制造业AI质检工作站助力制造业实现AI智检
人工智能·算法·自动化
嵌入式小能手10 小时前
飞凌嵌入式ElfBoard-进程间的通信之命名管道
linux·服务器·算法
啦哈拉哈10 小时前
Leetcode题解记录-hot100(81-100)
算法·leetcode·职场和发展
csdn_aspnet11 小时前
Java 霍尔分区算法(Hoare‘s Partition Algorithm)
java·开发语言·算法
诸葛务农11 小时前
道路行驶条件下电动汽车永磁电机的有效使用寿命及永磁体的失效和回收再利用(下)
java·开发语言·算法
snow@li11 小时前
AI:理解 大数据、算法、算力、电力、生成式AI、token 之间的关系
大数据·人工智能·算法