LeetCode 15 三数之和

点此看全部题解 LeetCode必刷100题:一份来自面试官的算法地图(题解持续更新中)

生活中的算法

想象你是一个收银员,顾客给了你一张100元钱,商品只要85元。你要从收银柜里找零15元,但是柜子里只有一堆1元、2元、5元、10元的零钱。你会怎么做?你可能会拿起一张5元,然后找另外两张,加起来正好等于15元。

这就是我们今天要讲的"三数之和"问题的现实版本。不过在算法题中,我们要找的不是指定的和,而是和为0的三个数。

问题描述

LeetCode第15题"三数之和"是这样描述的:给你一个整数数组nums,请你找出所有和为0且不重复的三元组。

例如,给定数组 nums = [-1,0,1,2,-1,-4],满足要求的三元组是:[[-1,-1,2], [-1,0,1]]

这个问题看似简单,但要处理好"不重复"这个要求,还真需要一些巧妙的思路。

最直观的解法:三重循环法

最容易想到的方法就是:用三重循环遍历所有可能的三元组组合。就像收银员可能会一张一张地尝试所有零钱的组合。

具体步骤是这样的:

  1. 用三层循环遍历所有可能的三元组
  2. 检查每个三元组的和是否为0
  3. 如果找到了和为0的三元组,还要检查是否重复

让我们用一个小例子来模拟这个过程:

nums = [-1,0,1]

尝试所有组合:
(-1,0,1): -1 + 0 + 1 = 0 ✓
(-1,1,0): -1 + 1 + 0 = 0 (重复)
(0,-1,1): 0 + -1 + 1 = 0 (重复)
... 最终结果:[[-1,0,1]]

这种思路可以用Java代码这样实现:

public List<List<Integer>> threeSum(int[] nums) {
Set<List<Integer>> result = new HashSet<>(); for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
for (int k = j + 1; k < nums.length; k++) {
if (nums[i] + nums[j] + nums[k] == 0) {
// 对三个数排序,以避免重复
List<Integer> triplet = Arrays.asList(nums[i], nums[j], nums[k]);
Collections.sort(triplet);
result.add(triplet);
}
}
}
} return new ArrayList<>(result);
}

优化解法:排序+双指针法

仔细想想,我们其实可以把问题转化为:固定一个数,然后在剩下的数中找两个数,使它们的和等于第一个数的相反数。这就变成了我们熟悉的"两数之和"问题!

关键是要先对数组排序,这样就可以:

  1. 方便地跳过重复的数字
  2. 使用双指针高效地寻找两个数

排序+双指针法的原理

  1. 先将数组排序
  2. 固定第一个数nums[i],目标变成找两个数之和等于-nums[i]
  3. 使用左右指针在nums[i]后面的区域寻找这两个数
  4. 根据三数之和与0的比较,移动左右指针
  5. 注意跳过重复的数字以避免重复的三元组

算法步骤(伪代码)

  1. 对数组排序
  2. 遍历数组,固定第一个数nums[i]:
    • 如果nums[i]大于0,后面不可能有解,直接结束
    • 如果nums[i]和前一个数相同,跳过以避免重复
    • 使用左右指针在[i+1, end]区间寻找两数之和等于-nums[i]的组合
  3. 记录所有找到的三元组

示例运行

让我们用例子[-1,0,1,2,-1,-4]模拟这个过程:

排序后:[-4,-1,-1,0,1,2]

固定-4:
目标找和为4的两个数
left=1,right=5: -1+2=1<4,left++
left=2,right=5: -1+2=1<4,left++
left=3,right=5: 0+2=2<4,left++
left=4,right=5: 1+2=3<4,结束 固定第一个-1:
目标找和为1的两个数
left=2,right=5: -1+2=1,找到[-1,-1,2]!
right--继续找... 固定第二个-1:(跳过,避免重复) 固定0:
目标找和为0的两个数
left=4,right=5: 1+2=3>0,right--
left=4,right=4:指针相遇,结束

Java代码实现

public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
// 先排序,这对去重和使用双指针非常关键
Arrays.sort(nums); for (int i = 0; i < nums.length - 2; i++) {
// 如果第一个数就大于0,后面肯定没有解
if (nums[i] > 0) break; // 跳过重复的第一个数
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) {
result.add(Arrays.asList(nums[i], nums[left], nums[right])); // 跳过重复的数
while (left < right && nums[left] == nums[left+1]) left++;
while (left < right && nums[right] == nums[right-1]) right--; // 继续寻找其他解
left++;
right--;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
} return result;
}

三重循环vs排序+双指针

让我们比较这两种解法:

三重循环法的时间复杂度是O(n³),空间复杂度是O(1)(不考虑存储结果的空间)。它的优点是直观易懂,缺点是效率太低。

排序+双指针法的时间复杂度是O(n²),其中排序占用O(nlogn)。空间复杂度是O(logn)到O(n),取决于排序算法的实现。它通过巧妙地利用排序数组的特性,将时间复杂度降低了一个维度。

题目模式总结

这道题体现了几个重要的算法思想:

  1. 问题转换:将三数之和转换为一个数加两数之和
  2. 排序预处理:通过排序简化后续的处理
  3. 双指针技巧:在排序数组中高效查找
  4. 去重处理:利用排序后的性质跳过重复元素

这种模式可以扩展到解决其他类似问题:

  • 四数之和
  • K数之和
  • 最接近的三数之和

解决这类问题的通用思路是:

  1. 考虑是否可以通过排序获得额外的性质
  2. 能否将K数之和转换为K-1数之和
  3. 如何高效地避免重复解

小结

通过这道题,我们不仅学会了如何高效地找出三数之和为0的组合,更重要的是理解了如何将一个复杂问题分解成更容易解决的子问题。这种思维方式在算法设计中非常重要。

记住,遇到复杂问题时,不要急于求解,先思考能否通过预处理(如排序)或问题转换来简化问题。有时候,看似复杂的问题,换个角度就豁然开朗!


作者:忍者算法
公众号:忍者算法

从找零钱问题到三数之和:一道经典面试算法题的全面剖析|LeetCode 15 三数之和的更多相关文章

  1. python经典面试算法题4.1:如何找出数组中唯一的重复元素

    本题目摘自<Python程序员面试算法宝典>,我会每天做一道这本书上的题目,并分享出来,统一放在我博客内,收集在一个分类中. [百度面试题] 难度系数:⭐⭐⭐ 考察频率:⭐⭐⭐⭐ 题目描述 ...

  2. python经典面试算法题1.3:如何计算两个单链表所代表的数之和

    本题目摘自<Python程序员面试算法宝典>,我会每天做一道这本书上的题目,并分享出来,统一放在我博客内,收集在一个分类中. 1.2 如何实现链表的逆序 [华为笔试题] 难度系数:⭐⭐⭐ ...

  3. leetcode:Path Sum (路径之和) 【面试算法题】

    题目: Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up ...

  4. Java实现 LeetCode 15 三数之和

    15. 三数之和 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以 ...

  5. LeetCode 15. 三数之和(3Sum)

    15. 三数之和 15. 3Sum 题目描述 Given an array nums of n integers, are there elements a, b, c in nums such th ...

  6. [Leetcode 15]三数之和 3 Sum

    [题目] Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? ...

  7. Java面试题精选(三) JSP/Servlet Java面试逻辑题

    --   JSP/Servlet  Java面试逻辑题   --     很显然,Servlet/JSP的WEB前端动态制作的重要性比HTML/CSS/JS的价值高很多,但我们都知道他们都是建立在HT ...

  8. LeetCode算法题-Move Zeroes(Java实现-三种解法)

    这是悦乐书的第201次更新,第211篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第67题(顺位题号是283).给定一个数组nums,写一个函数将所有0移动到它的末尾,同 ...

  9. LeetCode 15. 三数之和(3Sum)

    题目描述 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复 ...

  10. LeetCode——15. 三数之和

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

随机推荐

  1. 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-5-创建首个自动化脚本(详细教程)

    1.简介 前面几篇宏哥介绍了两种(java和maven)环境搭建和浏览器的启动方法,这篇文章宏哥将要介绍第一个自动化测试脚本.前边环境都搭建成功了,浏览器也驱动成功了,那么我们不着急学习其他内容,首先 ...

  2. Docker镜像管理之Harbor

    github: https://github.com/goharbor/harbor 官网:https://goharbor.io/docs/2.5.0/ [安装] 1. 查看是否达到安装条件 2.根 ...

  3. elasticsearch之python操作

    总结使用python对于elasticsearch的常用操作 安装 pip install elasticsearch 2. 连接 from elasticsearch import Elastics ...

  4. 设计模式【3.3】-- CGLIB动态代理源码解读

    cglib 动态代理 cglib介绍 CGLIB 是一个开源项目,一个强大高性能高质量的代码生成库,可以在运行期拓展 Java 类,实现 Java 接口等等.底层是使用一个小而快的字节码处理框架 AS ...

  5. 网站刚上线,就被 DDoS 攻击炸了!

    今天是一个值得纪念的日子,你打开一罐可乐,看着自己刚刚上线的小网站,洋洋得意. 这是你第一次做的网站,上线之后,网站访问量突飞猛进:没过多久,你就拿到了千万的风投,迎娶了女神,走上了人生巅峰... 害 ...

  6. 授权|取消授权MYSQL数据库用户权限

    授权 queryusr用户查询test数据库 grant select on test.* to queryusr@'%'; flush PRIVILEGES 收回queryusr用户查询test数据 ...

  7. 打破格式壁垒 !COS助力腾讯文档优化在线预览效果

    说起腾讯文档,相信大家对此并不陌生.在新冠疫情防控期间,腾讯文档在人员流动排查.健康信息收集.居家学习.协同办公等场景发挥了巨大的作用. 腾讯文档不仅支持新建word.excel.ppt.思维导图.流 ...

  8. 2024年1月Java项目开发指南16:用户自由选择字段查询、是否模糊查询

    我们希望用户可以自己控制是否要模糊查询 用户可以自由的选择字段去查询. 如上图,我在前端页面准备了 多选框:决定是否模糊查询.(True or False) 下拉选择框:决定要查询关键词的所属字段 输 ...

  9. 【前端】【JavaScript】简单的加减乘除计算器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 【前端】【Vue】Vue3自适应瀑布流解决方案

    Vue3自适应瀑布流解决方案 效果如上图所示. 说明:Vue3.[vue-masonry插件](vue-masonry - npm (npmjs.com)) 建议查看官方文档vue-masonry ( ...