两数之和(Hash表)

优质博文:IT-BLOG-CN

一、题目

给定一个整数数组nums和一个整数目标值target,请你在该数组中找出"和"为目标值target的那两个整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为nums[0] + nums[1] == 9,返回[0, 1]

示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案

进阶: 你可以想出一个时间复杂度小于O(n2)的算法吗?

二、代码

哈希表思路:
【1】先获取数组中的第一个元素,通过target - num[i] = x,直接过去x的下标,存在直接返回当前索引和查询到的索引,但需要对[3,3]=6等特殊场景进行处理。
【2】们发现这个题目属于hash表下面的,所以使用hash表来实现。可以用key保存数值,用value在保存数值所在的下标map中的存储结构为{key:数据元素,value:数组元素对应的下表}

在遍历数组的时候,只需要向map去查询是否存在target - num[i] = x中的x,如果存在,就返回value也就是下标和i,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。

class Solution {public int[] twoSum(int[] nums, int target) {// 先获取数组中的第一个元素,通过 target - num[i] = x, 直接过去x的下标,存在直接返回,需要对[3,3]相同的做特殊处理。// 我们发现这个题目属于 hash表下面的,所以使用hash表来实现。可以用key保存数值,用value在保存数值所在的下标// map中的存储结构为 {key:数据元素,value:数组元素对应的下表}int[] res = new int[2];Map<Integer,Integer> map = new HashMap();for (int i = 0; i < nums.length; i++) {int x = target - nums[i];if (map.containsKey(x)) {res[0] = map.get(x);res[1] = i;return res;}map.put(nums[i], i);}return res;}
}

时间复杂度: O(N),其中N是数组中的元素数量。对于每一个元素x,我们可以O(1)地寻找target - x
空间复杂度: O(N),其中N是数组中的元素数量。主要为哈希表的开销。

暴力枚举: 最容易想到的方法是枚举数组中的每一个数x,寻找数组中是否存在target - x

当我们使用遍历整个数组的方式寻找target - x时,需要注意到每一个位于x之前的元素都已经和x匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要在x后面的元素中寻找target - x

class Solution {public int[] twoSum(int[] nums, int target) {int n = nums.length;for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {if (nums[i] + nums[j] == target) {return new int[]{i, j};}}}return new int[0];}
}

时间复杂度: O(N^2),其中N是数组中的元素数量。最坏情况下数组中任意两个数都要被匹配一次。
空间复杂度: O(1)

思考:
1、如果nums是有序的,是否还需要哈希表?换句话说,能否做到O(1)额外空间?
2、如果要求寻找三个数,它们的和等于target呢?

含有重复元素的两数之和(字节算法工程师面试题) :给定一个可能包含重复元素的有序数组,以及一个目标值target。计算数组中有多少对两个整数的组合满足和等于target
示例1: nums=[2,2,2,2], target= 4, ans=6
示例2: nums=[1,1,2,2,2,2,3,3], target=4, ans=10
示例3: nums=[1,1,1,1], target=4, ans=0

其实第一眼看上去倒也不难,就是一个变体的两数之和。所以刚开始的思路就是先统计每一个数出现的次数,然后再按照两数之和的方法去算,只不过算的时候要考虑两个数出现的次数相乘才是所有的组合。

但是面试官说还有更好的,让我往三数之和上想。但是我想偏了,我一直想的是在三数之和中如果当前数和前一个数相等,那么会直接跳过。这里的话应该是可以根据前一个数对答案的贡献度直接推出来当前数的贡献度的。比如[1,1,2,2,2,2,4,4]的测试用例,首先第一次计算出第一个1对结果的贡献度是2之后,指针右移,又遇到一个1,那么可以不用计算,直接加上上一次的答案,同理,第一次遇到2也是,但是由于2 = 4 - 2,所以,第二次遇到2的时候,不能直接加上上一次的答案,应该加上上一次的答案-1

import bisect
def solve(nums, target):ans = 0pre = 0for i, num in enumerate(nums):if num == target - num:r = bisect.bisect_right(nums, num)ans += (r - i) * (r - i - 1) // 2return ansif i > 0 and nums[i-1] == num:ans += precontinuel, r = bisect.bisect_left(nums, target - num), bisect.bisect_right(nums, target - num)if l < r:ans += r - lpre = r - lreturn ans

面试完又想了一下另一个思路,可以按照三数之和内层循环的思路,用两个指针分别指向首尾,
1、如果这两个数的和小于taregt,右移左指针,
2、如果大于target,左移右指针。
3、如果等于target,分情况讨论
4、如果两个数相等,可以直接计算,然后终止循环。因为数组有序,继续循环下去也没意义。
5、如果两个数不相等,分别计算出左右两个数出现的次数。然后再计算对答案的贡献度。

时间复杂度: 因为每个数最多只会遍历一次,所以是O(n)
空间复杂度: 只需要常数级的额外空间,所以是:O(1)

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:ans = 0left, right = 0, len(nums) - 1while left <= right:current_sum = nums[left] + nums[right]if current_sum == target:# 找到一组满足条件的组合if nums[left] == nums[right]:ans += (right - left + 1) * (right - left) // 2break# 统计左右两个数各自出现的次数left_num, right_num = 1, 1left += 1right -= 1while left <= right and nums[left] == nums[left - 1]:left_num += 1left += 1while left <= right and nums[right] == nums[right + 1]:right_num += 1right -= 1ans += left_num * right_numelif current_sum < target:left += 1else:right -= 1return ans

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63105.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++8--赋值运算符重载

1.运算符重载 C引入运算符的目的是为了增强代码的可读性。运算符重载是具有特殊函数名的函数&#xff0c;也具有其返回值类型&#xff0c;函数名字以及参数列表&#xff0c;其返回值类型与参数列表与普通的函数相似。 函数名字为&#xff1a;关键字operator后面接需要重载的运算…

P1255 数楼梯

刚开始使用暴力进行求解&#xff0c;结果发现这是一道考验高精度的题目&#xff0c;后来用高精度的方法&#xff0c;甚至使用到了容器&#xff0c;结果还不如暴力求解的60分&#xff0c;后来看了题解&#xff0c;有一个非常好的思路&#xff0c;即体现了高精度求和&#xff0c;…

pyfink1.20版本下实现消费kafka中数据并实时计算

1、环境 JDK版本&#xff1a;1.8.0_412python版本&#xff1a;3.10.6apache-flink版本&#xff1a;1.20.0flink版本&#xff1a;1.20kafka版本&#xff1a;kafka_2.12-3.1.1flink-sql-connector-kafka版本&#xff1a;3.3.0-1.202、执行python-flink脚本 从kafka的demo获取消…

数据结构速成

1. 数据结构与算法 2. 顺序表 3. 链表 4. 栈与队列 5. 串 6. 树与二叉树&#xff08;1&#xff09; 7. 树与二叉树&#xff08;2&#xff09; 8. 图 9. 图的应用 10. 查找 11. 排序&#xff08;1&#xff09; 12. 排序&#xff08;2&#xff09;

k8s的污点与容忍度

污点&#xff08;Taint&#xff09;针对节点来说&#xff0c;和节点亲和性正好相对&#xff0c;节点亲和性使Pod被吸引到一类特定的节点&#xff0c;而污点则使节点能够排斥一类特定的Pod。 容忍度&#xff08;Toleration&#xff09;应用于Pod上&#xff0c;它用来允许调度器…

how to write 述职pptx as a tech manager

As a technical manager, crafting an effective 述职 (performance review) PPT requires you to highlight your leadership, team accomplishments, technical contributions, challenges faced, and future plans. Heres a structured approach to design your PPT: 1. Cov…

从源码层级深入探索 Spring AMQP 如何在 Spring Boot 中实现 RabbitMQ 集成——消费者如何进行消费

本章节主要从底层源码探索Spring Boot中RabbitMQ如何进行消费&#xff0c;至于RabbitMQ是如何使用如何生产消息&#xff0c;本章不做过多介绍&#xff0c;感兴趣的小伙伴可以参考&#xff1a;从源码层级深入探索 Spring AMQP 如何在 Spring Boot 中实现 RabbitMQ 集成——生产者…

计算机视觉中的边缘检测算法

摘要&#xff1a; 本文全面深入地探讨了计算机视觉中的边缘检测算法。首先阐述了边缘检测的重要性及其在计算机视觉领域的基础地位&#xff0c;随后详细介绍了经典的边缘检测算法&#xff0c;包括基于梯度的 Sobel 算子算法、Canny 边缘检测算法等&#xff0c;深入剖析了它们的…

Unix 和 Windows 的有趣比较

Unix 和 Windows NT 比较 来源于这两本书&#xff0c;把两本书对照来读&#xff0c;发现很多有意思的地方&#xff1a; 《Unix 传奇》 https://book.douban.com/subject/35292726/ 《观止 微软创建NT和未来的夺命狂奔 》 Showstopper!: The Breakneck Race to Create Windows…

SSM 垃圾分类系统——高效分类的科技保障

第五章 系统功能实现 5.1管理员登录 管理员登录&#xff0c;通过填写用户名、密码、角色等信息&#xff0c;输入完成后选择登录即可进入垃圾分类系统&#xff0c;如图5-1所示。 图5-1管理员登录界面图 5.2管理员功能实现 5.2.1 用户管理 管理员对用户管理进行填写账号、姓名、…

系列1:基于Centos-8.6部署Kubernetes (1.24-1.30)

每日禅语 “木末芙蓉花&#xff0c;山中发红萼&#xff0c;涧户寂无人&#xff0c;纷纷开自落。​”这是王维的一首诗&#xff0c;名叫《辛夷坞》​。这首诗写的是在辛夷坞这个幽深的山谷里&#xff0c;辛夷花自开自落&#xff0c;平淡得很&#xff0c;既没有生的喜悦&#xff…

Y20030004基于asp.net+Sql的环保网站的设计与实现(附源码 调试 文档)

环保网站的设计与实现 1.摘要要2. 系统功能3.功能结构图4.界面展示5.源码获取 1.摘要要 近几年国家对于环境管理是高度重视&#xff0c;尤其是对于环境生态的破坏与环境污染&#xff0c;已经严重影响到人类的生存和发展。为了使生态环境能够得到保护和改善&#xff0c;持续发展…

安全计算环境-(一)路由器-1

安全计算环境-网络设备 安全管理中心针对整个系统提出了安全管理方面的技术控制要求&#xff0c;通过技术手段实现集中管理&#xff1b;涉及的安全控制点包括系统管理、审计管理、安全管理和集中管控。以下以三级等级保护对象为例&#xff0c;描述安全管理中心各个控制要求项的…

D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。

概述&#xff1a; D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。 主要特点&#xff1a; ● 高精度基准电路 ● 定时闩锁、短路保护电路 ● 低电压输入时误操作保护电路 ● 输出基准电压(2.5V) ● 超过工作范围能进行自动校…

数据挖掘之聚类分析

聚类分析&#xff08;Clustering Analysis&#xff09; 是数据挖掘中的一项重要技术&#xff0c;旨在根据对象间的相似性或差异性&#xff0c;将对象分为若干组&#xff08;簇&#xff09;。同一簇内的对象相似性较高&#xff0c;而不同簇间的对象差异性较大。聚类分析广泛应用…

Qt 图形框架下图形拖动后位置跳动问题

在使用Qt 的图形框架QGraphicsScene&#xff0c;QGraphicsView实现图形显示时。遇到一个很棘手的BUG。 使用的图形是自定义的QGraphicsObject的子类。 现象是将图形添加到画布上之后&#xff0c;用鼠标拖动图形&#xff0c;图形能正常改变位置&#xff0c;当再次用鼠标点击图…

Vue技术中参数传递:Props与事件的实践指南

在Vue.js中&#xff0c;组件间的参数传递是构建动态和交互式应用的核心。本文将深入探讨如何通过Props和事件&#xff08;$emit&#xff09;在Vue组件间进行参数传递&#xff0c;并提供代码示例。 Props传递数据 Props是Vue中组件间传递数据的一种方式&#xff0c;它允许父组…

一、LRU缓存

LRU缓存 1.LRU缓存介绍2.LRU缓存实现3.LRU缓存总结3.1 LRU 缓存的应用3.2 LRU 缓存的优缺点 1.LRU缓存介绍 LRU是Least Recently Used 的缩写&#xff0c;意为“最近最少使用”。它是一种常见的缓存淘汰策略&#xff0c;用于在缓存容量有限时&#xff0c;决定哪些数据需要被删…

LabVIEW光栅衍射虚拟仿真系统

随着现代教育技术的快速发展&#xff0c;虚拟仿真实验平台逐渐成为物理实验教学的重要辅助工具。基于LabVIEW的平面透射光栅虚拟仿真系统帮助学生更好地理解和分析光栅衍射现象&#xff0c;提高教学质量和学生的学习兴趣。 项目背景 在波动光学的教学中&#xff0c;光栅衍射实…

241211 selenium问题记录

The process started from chrome location /usr/bin/chromedriver is no longer running, so ChromeDriver is assuming that Chrome has crashed. 声明option类 chrome_option.add_argument(--headless) 后台启动webdriver NoSuchDriverException(msg) from err selenium.c…