每日一题--数组中只出现一次的两个数字
数组中只出现一次的两个数字
- 题目描述
- 数据范围
- 提示
- 示例
- 示例1
- 示例2
- 题解
- 解题思路
- 位运算方法
- 步骤:
- 代码实现
- 代码解析
- 时间与空间复杂度
- 按位与操作获取最小位1的原理
- 为什么选择最低有效的 1 位而不是其他位?
题目描述
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
数据范围
- 数组长度:
2 ≤ n ≤ 1000 - 数组元素值:
0 < val ≤ 1000000
要求:
- 时间复杂度:
O(n) - 空间复杂度:
O(1)
提示
- 输出时按非降序排列。
示例
示例1
输入:
[1,4,1,6]
返回值:
[4,6]
说明:
- 返回的结果中较小的数排在前面。
示例2
输入:
[1,2,3,3,2,9]
返回值:
[1,9]
题解
解题思路
本题要求找出数组中出现一次的两个数字。由于数组中只有两个数字出现一次,其他数字都出现了两次。我们可以利用 位运算 来高效求解。
位运算方法
-
异或运算:我们可以利用异或(^)的特性来解决这个问题。异或运算有以下特点:
a ^ a = 0,即相同的数字异或结果为0;a ^ 0 = a,即任何数字与0异或结果为其本身;- 异或运算具有交换律和结合律。
-
求解步骤:
- 将数组中的所有数字进行异或。由于其他数字都出现了两次,它们的异或结果为0,最后剩下的就是两个只出现一次的数字的异或结果。
- 假设这两个只出现一次的数字为
x和y,那么x ^ y就是一个非0的值。我们可以根据x ^ y的二进制表示找到x和y的不同位。 - 通过分组操作,将所有数字根据该位进行分组,这样就可以分别找到
x和y。
步骤:
- 对数组中的所有元素进行异或,得到
xor。 - 找到
xor中某一位的为1的位置(即xor中第一个为1的位置),这表示x和y在这一位上不同。 - 根据该位置将所有数字分为两组,分别对每组中的数字异或,得到的结果即为
x和y。
代码实现
/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param nums int整型一维数组* @param numsLen int nums数组长度* @return int整型一维数组* @return int* returnSize 返回数组行数*/
int* FindNumsAppearOnce(int* nums, int numsLen, int* returnSize ) {*returnSize = 2;int* result = (int*)malloc(*returnSize * sizeof(int));int xor = 0;for (int i = 0; i < numsLen; i++) {xor ^= nums[i];}int right1 = xor &(-xor);*result = 0; // 初始化结果数组*(result + 1) = 0;for (int i = 0; i < numsLen; i++) {if ((nums[i]&right1) !=0)*result ^= nums[i];else*(result + 1) ^= nums[i];}if(*(result + 1)<*result){*(result + 1)^=*result;*result^=*(result + 1);*(result + 1)^=*result;}return result;// write code here
}
代码解析
-
第一步:我们通过对所有数字进行异或得到
xorResult,这个值是两个只出现一次的数字的异或结果。 -
第二步:我们找到
xorResult中最低为1的位。通过xorResult & (-xorResult)操作,即xorResult & (~xorResult+1)我们获取到这一位的值。 -
第三步:根据该位的值将数组中的元素分为两组:
- 如果该位为1,则将元素分配到一组(在
num1中异或); - 如果该位为0,则将元素分配到另一组(在
num2中异或)。
- 如果该位为1,则将元素分配到一组(在
-
第四步:异或操作后,
num1和num2就分别是我们要找的两个只出现一次的数字。 -
返回结果:最后,我们返回按非降序排列的两个数字。
时间与空间复杂度
- 时间复杂度:
O(n),我们遍历了一遍数组进行异或运算。 - 空间复杂度:
O(1),我们只用了常数空间来存储临时变量。
要理解为什么xorResult & (-xorResult)(或者等价的xorResult & (~xorResult + 1)) 能得到xorResult中最低有效的1位的值,我们需要从二进制和补码的角度来分析。
按位与操作获取最小位1的原理
xorResult & (-xorResult) 的效果依赖于补码的特性。我们逐步解析这个过程:
xorResult中最低有效的1位前的所有位都是0或者1,而这个最低有效的1位后的所有位都应该是0。-xorResult是xorResult取反再加 1 的结果,它和xorResult在最低有效1位之前的二进制位完全相反,且在最低有效1位后面与xorResult的二进制位相同。
让我们举一个具体的例子,假设 xorResult = 12,其二进制表示为:
x o r R e s u l t = 00000000000000000000000000001100 xorResult = 00000000 00000000 00000000 00001100 xorResult=00000000000000000000000000001100
-xorResult(即 ~xorResult + 1)为:
− x o r R e s u l t = 11111111111111111111111111110100 -xorResult = 11111111 11111111 11111111 11110100 −xorResult=11111111111111111111111111110100
然后进行按位与操作:
x o r R e s u l t & ( − x o r R e s u l t ) = 00000000000000000000000000001100 & 11111111111111111111111111110100 = 00000000000000000000000000000100 xorResult \& (-xorResult) = 00000000 00000000 00000000 00001100 \& 11111111 11111111 11111111 11110100 = 00000000 00000000 00000000 00000100 xorResult&(−xorResult)=00000000000000000000000000001100&11111111111111111111111111110100=00000000000000000000000000000100
得到的结果是:
00000000000000000000000000000100 00000000 00000000 00000000 00000100 00000000000000000000000000000100
这个结果是 4,也就是最低有效 1 位的值。
为什么选择最低有效的 1 位而不是其他位?
最后得到的xor是所有的异或位,a^b,如果最低为为1,说名最低有效的 1 位,是因为它是异或结果中最早出现的差异位,它能够最早地分割数组,使得我们能更快地定位到这两个不同的数字。分割成两组,一组为这位是1和多个出现两次的数,然后,一组为这位是0和多个出现两次的数,多个出现两次的数异或后为0。所以解决
相关文章:
每日一题--数组中只出现一次的两个数字
数组中只出现一次的两个数字 题目描述数据范围提示 示例示例1示例2 题解解题思路位运算方法步骤: 代码实现代码解析时间与空间复杂度按位与操作获取最小位1的原理为什么选择最低有效的 1 位而不是其他位? 题目描述 一个整型数组里除了两个数字只出现一次…...
React Hooks 与 Class 组件相比有何优势
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
浏览器的缓存方式几种
浏览器的缓存方式主要分为以下几种: 1. 强制缓存(强缓存 / Memory Cache & Disk Cache) 通过 Expires 或 Cache-Control 头部控制。在缓存有效期内,浏览器直接使用缓存,不发起请求。 关键HTTP头: Ex…...
新装windows系统配置
安装windows 将windows镜像iso工具刻录到u盘里。开机选择u盘启动&安装激活。Win10专业版用户请在命令提示符窗口中依次输入:slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GXslmgr /skms kms.03k.orgslmgr /ato系统安装完成后,可以到https://www.microsof…...
Racecar Gym 总结
1.Racecar Gym 简介 Racecar Gym 是一个基于 PyBullet 物理引擎 的自动驾驶仿真平台,提供 Gymnasium(OpenAI Gym) 接口,主要用于强化学习(Reinforcement Learning, RL)、多智能体竞速(Multi-Ag…...
活动预告 |【Part1】 Azure 在线技术公开课:迁移和保护 Windows Server 和 SQL Server 工作负载
课程介绍 通过 Microsoft Learn 免费参加 Microsoft Azure 在线技术公开课,掌握创造新机遇所需的技能,加快对 Microsoft 云技术的了解。参加我们举办的“迁移和保护 Windows Server 和 SQL Server 工作负载”活动,了解 Azure 如何为将工作负…...
可视化大屏的热力图,显示热点事件最直观。
可视化大屏的热力图在显示热点事件方面之所以直观,主要有以下原因: 视觉呈现特点 颜色直观表意:热力图通过不同的颜色来表示数据的密度或强度。通常情况下,红色等暖色调表示高密度或高热度区域,代表热点事件发生较为…...
认识Electron 开启新的探索世界一
一、Electron轻松入门 1.搭建开发环境: 一般情况下开发者会使用node.js来创建electron项目,node.js是一个基于Chrome V8引擎的javascript运行环境,所以首先需要到官网去下载安装node.js 下载链接:https://nodejs.org/enhttps://no…...
每日一题洛谷P5733 【深基6.例1】自动修正c++
#include<iostream> #include<string> using namespace std; int main() {string t;cin >> t;for (int i 0; i < t.length(); i){if (t[i] > a && t[i] < z){t[i] A - a;}cout << t[i];}return 0; }...
鸿蒙音视频播放器:libwlmedia
libwlmedia 跨平台播放器wlmedia现在已经支持了鸿蒙(Harmony)平台了,SDK插件地址:libwlmedia 一、接入SDK 1.1 导入SDK ohpm i ywl5320/libwlmedia1.2 添加权限(可选) 如果需要播放网络视频,需要添加网络权限 #m…...
CF998A Balloons 构造
Balloons 算法:构造 rating : 1000 思路: 分情况讨论: 1. 当只有一个气球包时,肯定不行 2.当有两个气球包时,若两个气球包的气球个数相同则不行 3.其余的情况都是可以的,题目问给格里高利的气球包数…...
分组加密算法CLEFIA
目录 (1)加密算法 轮函数 F函数 线性变换 (2)解密算法 (3)密钥扩展算法 分组加密算法CLEFIA CLEFIA分组密码算法由日本Sony(索尼)公司设计开发,接口对应于128比特分组密码技术例如ISO/IEC18033-3国际标准和高级加密标准(AES)。算法的分组长度是128比特,密钥长度…...
3.3 VO-O(算子)语法
VO-O语法部分是VO语言的特色部分。其核心概念主要有两个,“算子”以及“数据连接”。使用者通过拖拽“算子”图元、配置“算子”参数、构建“算子”间的“数据连接”,最终形成一个具有数据流转关系的流程图。该流程图可被理解为是由VO语言编写的一段程序…...
C++模板学习从专家到入门:关键字typename与class
文章目录 共同点typename特性class特性 共同点 在定义类模板或者函数模板时,typename 和 class 关键字都可以用于指定模板参数中的类型。 template <class T> template <typename T>typename特性 C 允许在类内定义类型别名,且其使用方法与…...
网络安全--边界安全
现在人们生活依赖互联网程度越来越高,网络安全也逐步进入人们日常视野,信用卡信息泄漏、开房记录被查询、商业机密泄漏等等;无不牵动着一个人、一个公司、甚至一个国家的神经。随着技术的发展,网络边界变得也越来越复杂࿰…...
2.攻防世界 backup
题目描述中提示,备份文件 进入题目页面如下 通用备份文件后缀名 .bak:这是最常见的备份文件后缀名之一,表示某个文件的备份版本。 .old:表示文件的旧版本或备份,通常用于系统更新时保存旧文件。 .backup:…...
如何在Windows上使用Docker
引言 WSL2(Windows Subsystem for Linux2)是微软开发的一种技术,允许在 Windows 操作系统上运行 Linux 环境。它提供了一个兼容层,使得用户可以在 Windows 系统中直接运行 Linux 命令行工具、应用程序和开发工具,而无需…...
气体控制器联动风机,检测到环境出现异常时自动打开风机进行排风;
一、功能:检测到环境出现异常时自动打开风机进行排风; 二、设备: 1.气体控制器主机:温湿度,TVOC等探头的主机,可上报数据,探头监测到异常时,主机会监测到异常可联动风机或声光报警…...
51单片机俄罗斯方块清屏函数
/************************************************************************************************************** * 名称:LED_Clr * 功能:清屏 * 参数:NULL * 返回:NULL * 备注:temp数组为动态显示数据ÿ…...
c++ haru生成pdf输出饼图
#define PI 3.14159265358979323846 // 绘制饼图的函数 void draw_pie_chart(HPDF_Doc pdf, HPDF_Page page, float *data, int data_count, float x, float y, float radius) { float total 0; int i; // 计算数据总和 for (i 0; i < data_count; i) { tot…...
sentinel的限流原理
Sentinel 的限流原理基于 流量统计 和 流量控制策略,通过动态规则对系统资源进行保护。其核心设计包括以下几个关键点: 流量统计模型:滑动时间窗口 Sentinel 使用 滑动时间窗口算法 统计单位时间内的请求量,相比传统的固定时间窗…...
[权限提升] Linux 提权 维持 — 系统错误配置提权 - 通配符(ws)注入提权
关注这个专栏的其他相关笔记:[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01:通配符(ws)注入提权原理 通配符注入提权的核心是利用通配符的扩展特性,在命令执行时生成意外的参数或文件名,从而改变命令的行…...
C++,STL容器 set/multiset:集合/多重集合深入解析
文章目录 一、容器概览二、核心特性对比三、基础操作详解四、关键成员函数解析五、底层实现探秘六、性能优化实践七、典型应用场景数据去重统计实时排行榜维护区间查询系统八、注意事项与陷阱元素不可变性自定义类型的比较函数迭代器失效问题进阶技巧:结合STL算法十、总结与选…...
Neo4j图数据库学习(二)——SpringBoot整合Neo4j
一. 前言 本文介绍如何通过SpringBoot整合Neo4j的方式,对图数据库进行简单的操作。 Neo4j和SpringBoot的知识不再赘述。关于Neo4j的基础知识,有兴趣可以看看作者上一篇的文章:Neo4j图数据库学习(一)——初识CQL 二. 前置准备 新建SpringBo…...
整合 Redis 分布式锁:从数据结构到缓存问题解决方案
引言 在现代分布式系统中,Redis 作为高性能的键值存储系统,广泛应用于缓存、消息队列、实时计数器等多种场景。然而,在高并发和分布式环境下,如何有效地管理和控制资源访问成为一个关键问题。Redis 分布式锁正是为了解决这一问题…...
使用AI Agents集成外部API开发智能客服解决方案(上)
生成式AI的出现已经彻底改变了传统客服,为开发者和企业提供了更快速、更准确、更个性化的响应能力。其中由大语言模型(LLM)驱动的AI代理能够分析复杂的客户咨询,访问多个数据源,并提供相关的详细答案。在本文中&#x…...
2025手机电池技术革新,
具有AlN势垒和AlGaN背势垒的硅基GaN HEMT在电池兼容电压下提供突破性的输出功率 新加坡的一个工程师团队声称,他们通过研究低压硅基GaN HEMT的双异质结构设计的潜力,开辟了新的天地。 这些研究人员认为,这类晶体管是5G频率范围2频段功率 具…...
现在中国三大运营商各自使用的哪些band频段
现在中国三大运营商4G和5G频段分配情况: 中国移动 4G频段: TD-LTE: Band 39:1880-1920MHz,实际使用1885-1915MHz。 Band 40:2300-2400MHz,实际使用2320-2370MHz。 Band 41:2515-26…...
Linux系统-centos防火墙firewalld详解
Linux系统-centos7.6 防火墙firewalld详解 1 firewalld了解 CentOS 7.6默认的防火墙管理工具是firewalld,它取代了之前的iptables防火墙。firewalld属于典型的包过滤防火墙或称之为网络层防火墙,与iptables一样,都是用来管理防火墙的工具&a…...
Java Stream API:高效数据处理的利器引言
Java Stream API:高效数据处理的利器引言 在 Java 编程中,数据处理是一项极为常见且关键的任务。传统的 for 循环在处理数据集合时,往往会导致代码变得冗长、复杂,这不仅增加了代码的编写难度,还降低了代码的可读性和…...
