作者 | 小灰

来源 | 程序员小灰(ID:chengxuyuanxiaohui)

前一段时间,我们介绍了LeetCode上面的一个经典算法题【两数之和问题】。

这一次,我们把问题做一下扩展,尝试在数组中找到和为“特定值”的三个数

题目的具体要求是什么呢?给定下面这样一个整型数组:

我们随意选择一个特定值,比如13,要求找出三数之和等于13的全部组合。

由于5+6+2=13, 5+1+7=13,3+9+1=13,所以最终的输出结果如下:

【5, 6,2】

【5, 1,7】

【3, 9,1】

小灰的思路,是把原本的“三数之和问题”,转化成求n次“两数之和问题”。

我们以上面这个数组为例,选择特定值13,演示一下小灰的具体思路:

第1轮,访问数组的第1个元素5,把问题转化成从后面元素中找出和为8(13-5)的两个数:

如何找出和为8的两个数呢?按照上一次所讲的,我们可以使用哈希表高效求解:

第2轮,访问数组的第2个元素12,把问题转化成从后面元素中找出和为1(13-12)的两个数:

第3轮,访问数组的第3个元素6,把问题转化成从后面元素中找出和为7(13-6)的两个数:

以此类推,一直遍历完整个数组,相当于求解了n次两数之和问题。

    public static List<List<Integer>> threeSum(int[] nums, int target) {List<List<Integer>> resultList = new ArrayList<>();for (int i = 0; i < nums.length; i++) {Map<Integer, Integer> map = new HashMap<>();int d1 = target - nums[i];//寻找两数之和等于d1的组合for (int j = i+1; j < nums.length; j++) {int d2 = d1 - nums[j];if (map.containsKey(d2)) {resultList.add(Arrays.asList(nums[i], d2, nums[j]));}map.put(nums[j], j);}}return resultList;}

在上面的代码中,每一轮解决“两数之和问题”的时间复杂度是O(n),一共迭代n轮,所以该解法总的时间复杂度是O(n²)

至于空间复杂度,同一个哈希表被反复构建,哈希表中最多有n-1个键值对,所以该解法的空间复杂度是O(n)

我们仍然以之前的数组为例,对数组进行升序排列:

这样说起来有些抽象,我们来具体演示一下:

第1轮,访问数组的第1个元素1,把问题转化成从后面元素中找出和为12(13-1)的两个数。

如何找出和为12的两个数呢?我们设置两个指针,指针j指向剩余元素中最左侧的元素2,指针k指向最右侧的元素12:

计算两指针对应元素之和,2+12 = 14 > 12,结果偏大了。

由于数组是按照升序排列,k左侧的元素一定小于k,因此我们把指针k左移一位:

计算两指针对应元素之和,2+9 = 11< 12,这次结果又偏小了。

j右侧的元素一定大于j,因此我们把指针j右移一位:

计算两指针对应元素之和,3+9 = 12,正好符合要求!

因此我们成功找到了一组匹配的组合:1,3,9

但这并不是结束,我们要继续寻找其他组合,让指针k继续左移:

计算两指针对应元素之和,3+7 = 10< 12,结果偏小了。

于是我们让指针j右移:

计算两指针对应元素之和,5+7 = 12,又找到符合要求的一组:

1,5,7

我们继续寻找,让指针k左移:

计算两指针对应元素之和,5+6 = 11< 12,结果偏小了。

于是我们让指针j右移:

此时双指针重合在了一起,如果再继续移动,就有可能和之前找到的组合重复,因此我们直接结束本轮循环。

第2轮,访问数组的第2个元素2,把问题转化成从后面元素中找出和为11(13-2)的两个数。

我们仍然设置两个指针,指针j指向剩余元素中最左侧的元素3,指针k指向最右侧的元素12:

计算两指针对应元素之和,3+12 = 15 > 11,结果偏大了。

我们让指针k左移:

计算两指针对应元素之和,3+9 = 12 > 11,结果仍然偏大。

我们让指针k继续左移:

计算两指针对应元素之和,3+7 = 10 < 11,结果偏小了。

我们让指针j右移:

计算两指针对应元素之和,5+7 = 12 > 11,结果又偏大了。

我们让指针k左移:

计算两指针对应元素之和,5+6 = 11,于是我们又找到符合要求的一组:

2,5,6

我们继续寻找,让指针k左移:

此时双指针又一次重合在一起,我们结束本轮循环。

按照这个思路,我们一直遍历完整个数组。

像这样利用两个指针指向数组两端,不断向中间靠拢调整来寻找匹配组合的方法,就是双指针法,也被称为“夹逼法”。

    public static List<List<Integer>> threeSumv2(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> resultList = new ArrayList<List<Integer>>();//大循环for (int i = 0; i < nums.length; i++) {int d = target - nums[i];// j和k双指针循环定位,j在左端,k在右端for (int j=i+1,k=nums.length-1; j<nums.length; j++) {// k指针向左移动while (j<k && (nums[j]+nums[k])>d) {k--;}//双指针重合,跳出本次循环if (j == k) {break;}if (nums[j] + nums[k] == d) {List<Integer> list = Arrays.asList(nums[i], nums[j], nums[k]);resultList.add(list);}}}return resultList;}

上面这段代码表面上有三层循环,但每一轮指针j和k的移动次数加起来最多n-1次,因此该解法的整体时间复杂度是O(n²)

最关键的是,该解法并没有使用额外的集合(排序是直接在输入数组上进行的),所以空间复杂度只有O(1)

更多精彩推荐
☞去伪存真,更多区块链落地应用即将涌现
☞你认为程序员的最高境界是什么?| 每日趣闻
☞虎牙、斗鱼正式达成合并协议;中国广电正式成立,或催生5G发展新格局;Linux 5.9 释出|极客头条
☞8000字 | 32 张图 | 一文搞懂事务+隔离级别+阻塞+死锁
☞图神经网络快速爆发,最新进展都在这里了
☞今年至少有75家交易所关闭,近半数没有说明原因
点分享点点赞点在看

漫画:如何在数组中找到和为 “特定值” 的三个数?相关推荐

  1. 漫画:如何在数组中找到和为 “特定值” 的两个数?

    作者 | 小灰 来源 | 程序员小灰(ID:chengxuyuanxiaohui) -----  第二天  ----- 什么意思呢?我们来举个例子,给定下面这样一个整型数组(题目假定数组不存在重复元素 ...

  2. java数组中最小的k个元素_java – 在数组中找到k个最小整数

    这是我的代码,它适用于查找1-7个最小整数,但是8和9.当我在数组中找到8个最小整数时,它返回null.任何人都可以帮我解决问题吗?我在这里使用quicksort. 非常感谢! 更新:我已经找到问题, ...

  3. python求无序列表中位数_python 实现在无序数组中找到中位数方法

    一.问题描述 1.求一个无序数组的中位数, (若数组是偶数,则中位数是指中间两个数字之和除以2,若数组是奇数,则中位数是指最中间位置.要求:不能使用排序,时间复杂度尽量低 2.例如:lists = [ ...

  4. 在数组中找到第 k 小的数

    在数组中找到第 k 小的数 [要求] 如果 arr 长度为 N,要求时间复杂度为 O(N),额外空间复杂度为 O(1). public static int[] getMinKNumByHeap(in ...

  5. 《程序员代码面试指南》第七章 位运算 在其他数都出现k 次的数组中找到只出现一次的数...

    题目 在其他数都出现k 次的数组中找到只出现一次的数 java 代码 package com.lizhouwei.chapter7;/*** @Description: 在其他数都出现k 次的数组中找 ...

  6. C语言数组中找到第一个重复元素的算法(附完整源码)

    C语言数组中找到第一个重复元素的算法 C语言数组中找到第一个重复元素的算法完整源码(定义,实现,main函数测试) C语言数组中找到第一个重复元素的算法完整源码(定义,实现,main函数测试) #in ...

  7. C语言在数组中找到最大的元素(附完整源码)

    C语言在数组中找到最大的元素 C语言在数组中找到最大的元素完整源码(定义,实现,main函数测试) C语言在数组中找到最大的元素完整源码(定义,实现,main函数测试) #include <io ...

  8. Java黑皮书课后题第7章:*7.20(修改选择排序法)在7.11节中,使用了选择排序法对数组排序。改写7.11节程序,重复地在当前数组中找到最大值,然后将这个最大值与该数组中的最后一个数进行交换

    7.20(修改选择排序法)在7.11节中,使用了选择排序法对数组排序.改写7.11节程序,重复地在当前数组中找到最大值,然后将这个最大值与该数组中的最后一个数进行交换 题目 题目描述 破题 代码 运行 ...

  9. 每天一道LeetCode-----在给定数组中找到一个子数组,使得这个子数组的元素乘积最大

    Maximum Product Subarray 原题链接Maximum Product Subarray 在给定数组中找到一个子数组,使得这个子数组元素的乘积最大.给定数组中可能有正数,负数和0 思 ...

最新文章

  1. couldn't connect to server 127.0.0.1:27017 src/mongo/
  2. 网站数据分析:基于用户细分的比较分析
  3. 【推荐系统】基于知识图谱的推荐系统总结
  4. 程序员30岁后,9分钟跑完1600米
  5. 内核探测工具systemtap简介
  6. 【转】3.5(译)构建Async同步基元,Part 5 AsyncSemaphore
  7. python下载网上的文件
  8. 专业课程设计之客户与服务器程序的同步与通信机制的设计(二)TCP通信
  9. SQL无所不能:DBA宝妈宝爸系列分享
  10. 全国计算机等级考试怎么保存,全国计算机等级考试一级备考:Word文档保存为PDF文件...
  11. 基于python的毕业设计仓库库存管理系统
  12. mac 修改 hosts 文件之后,刷新 DNS 缓存
  13. 微信小程序区分开发版、体验版和正式版
  14. 程炳皓:关于技术领导力,十个耸人听闻的观点
  15. 人人商城php环境,关于微擎人人商城互动直播通信服务安装和启动教程记录
  16. 清华姚班和清华计算机系,到底什么是清华姚班,姚班和智班哪个更厉害?不妨来了解一下...
  17. python读取中文txt乱码问题
  18. Ubuntu16.04 + Geforce GT630 OEM安装cuda 8.0
  19. 李小龙私人的超级训练计划
  20. 【笔记】《结网:互联网产品经理改变世界》

热门文章

  1. 拼多多创始人黄峥,要彻底卸下担子,搞“科研”去了。
  2. 抛弃Anchor box和NMS,目标检测新范式开源:Sparse R-CNN
  3. 3d 行为树编辑器_cocos creator主程入门教程——有限状态机和行为树
  4. SAP MM 如何看一个Inbound Delivery单据相关的IDoc?
  5. SAP MM 特殊库存之T库存
  6. Resnet对应于ImageNet的结构框架
  7. 机器学习系列19:将核函数应用于支持向量机
  8. 科大讯飞年报出炉,2018每天赚148万元,53%是政府补助
  9. 从SAP APO到SAP IBP:CIO如何实现最佳过渡?
  10. 业界丨2018,人工智能革命走向风口浪尖