当前位置: 首页 > article >正文

【Leetcode刷题记录】15.三数之和

15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 
满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。
请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

📑排序+双指针

对于这道题,最先想到的可能就是三重循环暴力枚举所有可能的三元组,但是这样做肯定是超时且不优雅的。因此要寻求一个更优化的解法,就是排序加双指针。

先对数组进行排序,这样做不仅有助于避免结果中的重复三元组,还为后续应用双指针奠定了基础。一旦数组被排完序,我们可以遍历数组中的每一个元素nums[i]将其作为潜在的三元组的第一个元素,对于每一个nums[i],现在的目标是找到另外两个元素nums[j]nums[k]k>j>i),使得nums[j]+nums[k]=-nums[i]

接下来就可以使用双指针来实现这一目标。在每次迭代中,我们设置两个指针:left指针初始化为i+1,指向当前元素之后的第一个位置;right指针则指向数组的最后一个元素。通过移动这两个指针,可以尝试找到满足条件的其他两个数。如果left指针和right指针所指向的数之和小于-nums[i],我们就增加left指针以尝试获得更大的值;反之,如果这个和大于-nums[i],我们就减少right指针以减小总和。当找到一组满足条件的三元组时,我们将它添加到结果集中。为了避免输出重复的答案,在发现一个有效的三元组之后,我们需要跳过所有与当前left或right指针对应的相同元素。

代码实现

vector<vector<int>> threeSum(vector<int>& nums) {
    sort(nums.begin(),nums.end());
    int n = nums.size();
    vector<vector<int>> res;
    for (int i = 0; i < n - 2; i++) {
        if (i > 0 && nums[i] == nums[i - 1])
            continue;
        int l = i + 1, r = n - 1;
        while (l < r) {
            if (nums[i] + nums[l] + nums[r] < 0) {
                l += 1;
            } else if (nums[i] + nums[l] + nums[r] > 0) {
                r -= 1;
            } else {
                res.push_back({nums[i], nums[l], nums[r]});
                // 去重
                while (l < r && nums[l] == nums[l + 1]) {
                    l += 1;
                }
                while (l < r && nums[r] == nums[r - 1]) {
                    r -= 1;
                }
                l += 1;
                r -= 1;
            }
        }
    }
    return res;
}

在这里插入图片描述

这里还有可以优化的点

  1. 如果当前元素与接下来两个最小的元素之和大于0,则直接终止循环
  2. 如果当前元素与最大的两个元素之和小于0,则跳过此次循环

下面是稍微优化后的代码

vector<vector<int>> threeSum(vector<int>& nums) {
    sort(nums.begin(), nums.end());
    int n = nums.size();
    vector<vector<int>> res;
    for (int i = 0; i < n - 2; i++) {
        // 提前终止条件1: 如果当前元素与接下来两个最小的元素之和大于0,则直接终止循环
        if (nums[i] + nums[i + 1] + nums[i + 2] > 0) break;
        // 提前终止条件2: 如果当前元素加上最大的两个元素之和仍小于0,则跳过此次迭代
        if (nums[i] + nums[n - 1] + nums[n - 2] < 0) continue;
        // 跳过重复项
        if (i > 0 && nums[i] == nums[i - 1]) continue;
        int l = i + 1, r = n - 1;
        while (l < r) {
            if (nums[i] + nums[l] + nums[r] < 0) {
                l += 1;
            } else if (nums[i] + nums[l] + nums[r] > 0) {
                r -= 1;
            } else {
                res.push_back({nums[i], nums[l], nums[r]});
                // 去重
                while (l < r && nums[l] == nums[l + 1]) l += 1;
                while (l < r && nums[r] == nums[r - 1]) r -= 1;
                l += 1;
                r -= 1;
            }
        }
    }
    return res;
}

在这里插入图片描述


http://www.kler.cn/a/519704.html

相关文章:

  • Linux 入门 常用指令 详细版
  • 网盘资源查找工具---AI功能
  • Spring集成Redis|通用Redis工具类
  • 可见光通信代码仿真
  • 996引擎 - NPC-动态创建NPC
  • 被占用的电脑文件推沟里
  • 【2024年华为OD机试】(A卷,200分)- 农场施肥 (JavaScriptJava PythonC/C++)
  • 2025年美赛(MCM/ICM)赛题浅析——助攻快速选题
  • 小智 AI 聊天机器人
  • Python读写各类数据文件
  • 学习数据结构(1)算法复杂度
  • JavaScript系列(44)--微服务架构实现详解
  • 【25考研】中科院软件考研复试难度分析!
  • leetcode 1358. 包含所有三种字符的子字符串数目
  • 【PostgreSQL内核学习 —— (WindowAgg(一))】
  • 基于vue框架的的信用社业务管理系统设计与实现4gnx5(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 包安装利用 LNMP 实现 phpMyAdmin 的负载均衡并利用Redis实现会话保持nginx
  • 如何优化企业的CRM流程管理?
  • 【知识图谱(2)】电影知识图谱构建
  • 【测试人生】变更风险观测的流程逻辑设计
  • Docker基础命令和配置镜像代理(最新)
  • 【竞技宝】DOTA2-裂变天地S1:XG遭遇二连败命悬一线
  • 二叉树的层序遍历||力扣--107
  • chrome插件:网页图片高清下载
  • 使用LPT wiggler jtag自制三星单片机(sam88 core)编程器-S3F9454
  • 网易Android开发面试题200道及参考答案 (上)