每日一题--数组中只出现一次的两个数字

news2025/2/10 9:25:29

数组中只出现一次的两个数字

    • 题目描述
      • 数据范围
      • 提示
    • 示例
      • 示例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]

题解

解题思路

本题要求找出数组中出现一次的两个数字。由于数组中只有两个数字出现一次,其他数字都出现了两次。我们可以利用 位运算 来高效求解。

位运算方法
  1. 异或运算:我们可以利用异或(^)的特性来解决这个问题。异或运算有以下特点:

    • a ^ a = 0,即相同的数字异或结果为0;
    • a ^ 0 = a,即任何数字与0异或结果为其本身;
    • 异或运算具有交换律和结合律。
  2. 求解步骤

    • 将数组中的所有数字进行异或。由于其他数字都出现了两次,它们的异或结果为0,最后剩下的就是两个只出现一次的数字的异或结果。
    • 假设这两个只出现一次的数字为 xy,那么 x ^ y 就是一个非0的值。我们可以根据 x ^ y 的二进制表示找到 xy 的不同位。
    • 通过分组操作,将所有数字根据该位进行分组,这样就可以分别找到 xy
步骤:
  1. 对数组中的所有元素进行异或,得到 xor
  2. 找到 xor 中某一位的为1的位置(即 xor 中第一个为1的位置),这表示 xy 在这一位上不同。
  3. 根据该位置将所有数字分为两组,分别对每组中的数字异或,得到的结果即为 xy

代码实现

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 *
 * @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
}

代码解析

  1. 第一步:我们通过对所有数字进行异或得到 xorResult,这个值是两个只出现一次的数字的异或结果。

  2. 第二步:我们找到 xorResult 中最低为1的位。通过 xorResult & (-xorResult) 操作,即xorResult & (~xorResult+1) 我们获取到这一位的值。

  3. 第三步:根据该位的值将数组中的元素分为两组:

    • 如果该位为1,则将元素分配到一组(在 num1 中异或);
    • 如果该位为0,则将元素分配到另一组(在 num2 中异或)。
  4. 第四步:异或操作后,num1num2 就分别是我们要找的两个只出现一次的数字。

  5. 返回结果:最后,我们返回按非降序排列的两个数字。

时间与空间复杂度

  • 时间复杂度O(n),我们遍历了一遍数组进行异或运算。
  • 空间复杂度O(1),我们只用了常数空间来存储临时变量。
    要理解为什么 xorResult & (-xorResult)(或者等价的 xorResult & (~xorResult + 1)) 能得到 xorResult 中最低有效的 1 位的值,我们需要从二进制和补码的角度来分析。

按位与操作获取最小位1的原理

xorResult & (-xorResult) 的效果依赖于补码的特性。我们逐步解析这个过程:

  • xorResult 中最低有效的 1 位前的所有位都是 0 或者 1,而这个最低有效的 1 位后的所有位都应该是 0
  • -xorResultxorResult 取反再加 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。所以解决

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

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

相关文章

React Hooks 与 Class 组件相比有何优势

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Racecar Gym 总结

1.Racecar Gym 简介 Racecar Gym 是一个基于 PyBullet 物理引擎 的自动驾驶仿真平台&#xff0c;提供 Gymnasium&#xff08;OpenAI Gym&#xff09; 接口&#xff0c;主要用于强化学习&#xff08;Reinforcement Learning, RL&#xff09;、多智能体竞速&#xff08;Multi-Ag…

活动预告 |【Part1】 Azure 在线技术公开课:迁移和保护 Windows Server 和 SQL Server 工作负载

课程介绍 通过 Microsoft Learn 免费参加 Microsoft Azure 在线技术公开课&#xff0c;掌握创造新机遇所需的技能&#xff0c;加快对 Microsoft 云技术的了解。参加我们举办的“迁移和保护 Windows Server 和 SQL Server 工作负载”活动&#xff0c;了解 Azure 如何为将工作负…

可视化大屏的热力图,显示热点事件最直观。

可视化大屏的热力图在显示热点事件方面之所以直观&#xff0c;主要有以下原因&#xff1a; 视觉呈现特点 颜色直观表意&#xff1a;热力图通过不同的颜色来表示数据的密度或强度。通常情况下&#xff0c;红色等暖色调表示高密度或高热度区域&#xff0c;代表热点事件发生较为…

认识Electron 开启新的探索世界一

一、Electron轻松入门 1.搭建开发环境&#xff1a; 一般情况下开发者会使用node.js来创建electron项目&#xff0c;node.js是一个基于Chrome V8引擎的javascript运行环境&#xff0c;所以首先需要到官网去下载安装node.js 下载链接&#xff1a;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; }

分组加密算法CLEFIA

目录 (1)加密算法 轮函数 F函数 线性变换 (2)解密算法 (3)密钥扩展算法 分组加密算法CLEFIA CLEFIA分组密码算法由日本Sony(索尼)公司设计开发,接口对应于128比特分组密码技术例如ISO/IEC18033-3国际标准和高级加密标准(AES)。算法的分组长度是128比特,密钥长度…

网络安全--边界安全

现在人们生活依赖互联网程度越来越高&#xff0c;网络安全也逐步进入人们日常视野&#xff0c;信用卡信息泄漏、开房记录被查询、商业机密泄漏等等&#xff1b;无不牵动着一个人、一个公司、甚至一个国家的神经。随着技术的发展&#xff0c;网络边界变得也越来越复杂&#xff0…

2.攻防世界 backup

题目描述中提示&#xff0c;备份文件 进入题目页面如下 通用备份文件后缀名 .bak&#xff1a;这是最常见的备份文件后缀名之一&#xff0c;表示某个文件的备份版本。 .old&#xff1a;表示文件的旧版本或备份&#xff0c;通常用于系统更新时保存旧文件。 .backup&#xff1a;…

如何在Windows上使用Docker

引言 WSL2&#xff08;Windows Subsystem for Linux2&#xff09;是微软开发的一种技术&#xff0c;允许在 Windows 操作系统上运行 Linux 环境。它提供了一个兼容层&#xff0c;使得用户可以在 Windows 系统中直接运行 Linux 命令行工具、应用程序和开发工具&#xff0c;而无需…

气体控制器联动风机,检测到环境出现异常时自动打开风机进行排风;

一、功能&#xff1a;检测到环境出现异常时自动打开风机进行排风&#xff1b; 二、设备&#xff1a; 1.气体控制器主机&#xff1a;温湿度&#xff0c;TVOC等探头的主机&#xff0c;可上报数据&#xff0c;探头监测到异常时&#xff0c;主机会监测到异常可联动风机或声光报警…

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…

[权限提升] Linux 提权 维持 — 系统错误配置提权 - 通配符(ws)注入提权

关注这个专栏的其他相关笔记&#xff1a;[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01&#xff1a;通配符&#xff08;ws&#xff09;注入提权原理 通配符注入提权的核心是利用通配符的扩展特性&#xff0c;在命令执行时生成意外的参数或文件名&#xff0c;从而改变命令的行…

C++,STL容器 set/multiset:集合/多重集合深入解析

文章目录 一、容器概览二、核心特性对比三、基础操作详解四、关键成员函数解析五、底层实现探秘六、性能优化实践七、典型应用场景数据去重统计实时排行榜维护区间查询系统八、注意事项与陷阱元素不可变性自定义类型的比较函数迭代器失效问题进阶技巧:结合STL算法十、总结与选…

Neo4j图数据库学习(二)——SpringBoot整合Neo4j

一. 前言 本文介绍如何通过SpringBoot整合Neo4j的方式&#xff0c;对图数据库进行简单的操作。 Neo4j和SpringBoot的知识不再赘述。关于Neo4j的基础知识&#xff0c;有兴趣可以看看作者上一篇的文章&#xff1a;Neo4j图数据库学习(一)——初识CQL 二. 前置准备 新建SpringBo…

使用AI Agents集成外部API开发智能客服解决方案(上)

生成式AI的出现已经彻底改变了传统客服&#xff0c;为开发者和企业提供了更快速、更准确、更个性化的响应能力。其中由大语言模型&#xff08;LLM&#xff09;驱动的AI代理能够分析复杂的客户咨询&#xff0c;访问多个数据源&#xff0c;并提供相关的详细答案。在本文中&#x…

2025手机电池技术革新,

具有AlN势垒和AlGaN背势垒的硅基GaN HEMT在电池兼容电压下提供突破性的输出功率 新加坡的一个工程师团队声称&#xff0c;他们通过研究低压硅基GaN HEMT的双异质结构设计的潜力&#xff0c;开辟了新的天地。 这些研究人员认为&#xff0c;这类晶体管是5G频率范围2频段功率 具…

Linux系统-centos防火墙firewalld详解

Linux系统-centos7.6 防火墙firewalld详解 1 firewalld了解 CentOS 7.6默认的防火墙管理工具是firewalld&#xff0c;它取代了之前的iptables防火墙。firewalld属于典型的包过滤防火墙或称之为网络层防火墙&#xff0c;与iptables一样&#xff0c;都是用来管理防火墙的工具&a…

Unity3D仿星露谷物语开发28之切换场景

1、目标 Player可以在Scene1_Farm和Scene2_Field之间自动切换。通过Trigger实现该功能。同时创建一个预设体绑定该功能&#xff0c;这样可以把预设体放到任何场景中&#xff0c;通过配置即可实现Player在Scene之间的自由切换。 2、创建场景切换的工具对象 在Hierarchy中&…

阿里通义实验室提出AnyStory:开启个性化文本到图像生成的新篇章!

在这个数字化时代&#xff0c;生成式AI技术正以前所未有的速度改变着我们的创作方式。近期&#xff0c;阿里通义实验室发表了一篇题为《AnyStory: Towards Unified Single and Multi-Subject Personalization in Text-to-Image Generation》的论文&#xff0c;该论文提出了一种…