01. Leetcode打卡 —— 三数之和

70 阅读2分钟

Offer 驾到,掘友接招!我正在参与 2022 春招系列活动-刷题打卡任务,点击查看活动详情

题目描述

给你一个包含 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]
输出: []

思路分析(排序 + 双指针)

  1. 特殊判断:如果数组为 null 或者长度小于 3,直接返回 []

  2. 对数组排序。因为要三个数相加等于 0,即三个数中一定会区分正负,排序后可以更好的进行数据筛选

  3. 遍历排序后的数组

    • nums[i] > 0, 则直接返回结果: 因为已经排序好,所以后面不可能有三个数加和等于 0。

    • 若遇到重复元素,则直接跳过: 避免出现重复解

    • 令左指针 left = index + 1,右指针 right = len - 1,当 left < right 时,执行循环:

      • nums[index] + nums[left] + nums[right] == 0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 left, right 移到下一位置,寻找新的解
      • 若 sum > 0,说明 nums[right] 太大,right--
      • 若 sum < 0,说明 nums[left] 太小,left++

AC 代码

impl Solution {
    pub fn three_sum(nums: Vec<i32>) -> Vec<Vec<i32>> {
        let mut ans = vec![];
        let len = nums.len();
        // 如果数组为 null 或者长度小于 3,直接返回 []
        if len < 3 {
            return ans;
        }

        let mut nums = nums;
        // 对数组排序
        nums.sort();

        let (mut index, mut left, mut right) = (0, 0, 0);
        // 遍历排序后的数组
        for index in 0..len {
            // 若 nums[i] > 0, 则直接返回结果
            if nums[index] > 0 {
                return ans;
            }
            // 若遇到重复元素,则直接跳过
            if (index > 0) && (nums[index] == nums[index - 1]) {
                continue;
            }
            // 左指针 left = index + 1
            left = index + 1;
            // 右指针 right = len - 1
            right = len - 1;
            // 当 left < right 时,执行循环
            while left < right {
            
                match nums[index] + nums[left] + nums[right] {
                    0 => { // 当 nums[index] + nums[left] + nums[right] == 0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 left, right 移到下一位置,寻找新的解
                        ans.push(vec![nums[index], nums[left], nums[right]]);
                        left += 1;
                        right -= 1;
                        while left < right && nums[left] == nums[left - 1] {
                            left += 1;
                        }
                        while left < right && nums[right] == nums[right + 1] {
                            right -= 1;
                        }
                    },
                    a if a > 0 => {right -= 1}, // 若 sum > 0,说明 nums[right] 太大,right--
                    _ => {left += 1}, // 若 sum < 0,说明 nums[left] 太小,left++
                }
            }
        }
        ans
    }
}

扩展题型

  • 数组求和
  • 双链表合并