【经典算法】LeetCode 136:只出现一次的数字(Java/C/Python3实现含注释说明,Easy)
个人主页: 进朱者赤
阿里非典型程序员一枚 ,记录平平无奇程序员在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名)
目录
- 题目描述
- 思路及实现
- 方式一:使用异或运算(推荐)
- 思路
- 代码实现
- Java版本
- C语言版本
- Python3版本
- 复杂度分析
- 方式二:哈希表
- 思路
- 代码实现
- Java版本
- C语言版本
- Python3版本
- 复杂度分析
- 总结
- 相似题目
- 其他小知识
- 几个有趣的位操作
- 1. 利用或操作 | 和空格将英文字符转换为小写
- 2. 利用与操作 & 和下划线将英文字符转换为大写
- 3. 利用异或操作 ^ 和空格进行英文字符大小写互换
- 4. 加一
- 5. 减一
- 其他
- 标签(题目类型):位运算
题目描述
136. 只出现一次的数字
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。示例 1 :输入:nums = [2,2,1]
输出:1
示例 2 :输入:nums = [4,1,2,1,2]
输出:4
示例 3 :输入:nums = [1]
输出:1
提示:1 <= nums.length <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104
除了某个元素只出现一次以外,其余每个元素均出现两次。
原题:
LeetCode: LeetCode 136
力扣 : 力扣 136
思路及实现
方式一:使用异或运算(推荐)
思路
利用异或运算的性质:任何数和0异或等于它本身,任何数和其自身异或等于0,异或运算满足交换律和结合律。因此,我们可以将数组中的所有数字进行异或运算,出现两次的数字会相互抵消,最终剩下的就是只出现一次的数字。
- 以[4,1,3,4,3]以例

面试官最期待的解法思路,考察计算机基础知识
代码实现
Java版本
class Solution {public int singleNumber(int[] nums) {int x = 0;for (int num : nums) // 1. 遍历 nums 执行异或运算x ^= num;return x; // 2. 返回出现一次的数字 x}
}
说明: 通过遍历数组中的每个数字,并使用异或运算将结果保存在result变量中,最终返回result即可。
C语言版本
#include <stdio.h>int singleNumber(int* nums, int numsSize) {int x = 0;for (int i = 0; i < numsSize; i++) { // 1. 遍历 nums 执行异或运算x ^= nums[i];}return x; // 2. 返回出现一次的数字 x
}
说明: 使用for循环遍历数组,将每个元素与result进行异或运算,并更新result的值。
Python3版本
class Solution:def singleNumber(self, nums: List[int]) -> List[int]:x = 0for num in nums: # 1. 遍历 nums 执行异或运算x ^= num return x; # 2. 返回出现一次的数字 x
说明: Python中的实现与Java和C类似,使用for循环遍历数组,并通过异或运算找出只出现一次的数字。
复杂度分析
- 时间复杂度:O(n),其中 n 是数组 nums 的长度。这是因为我们只需要遍历一次数组,对每个元素进行一次异或操作。
- 空间复杂度:O(1),因为我们只使用了常数个额外的变量来存储中间结果,与输入数组的大小无关。
方式二:哈希表
思路
使用哈希表记录每个数字出现的次数,最后找到出现次数为 1 的数字即为答案。
下面以HashMap为例,HashSet也是可以的
代码实现
Java版本
class Solution {public int singleNumber(int[] nums) {Map<Integer, Integer> counts = new HashMap<>();for (int num : nums) {counts.put(num, counts.getOrDefault(num, 0) + 1); // 统计每个数字出现的次数}for (int num : counts.keySet()) {if (counts.get(num) == 1) {return num; // 返回出现次数为 1 的数字}}return -1; //理论上不会到达这里}
}
说明:
创建一个哈希表 counts,用于存储每个数字出现的次数。
遍历数组 nums,统计每个数字出现的次数并更新到 counts 中。
遍历 counts,找到出现次数为 1 的数字并返回。
C语言版本
#include <stdio.h>
#include <stdlib.h>// 假设数字范围在 0 到 10000 之间,可以使用数组模拟哈希表
int singleNumber(int* nums, int numsSize) {int counts[10001] = {0};for (int i = 0; i < numsSize; i++) {counts[nums[i]]++; // 统计每个数字出现的次数}for (int i = 0; i < 10001; i++) {if (counts[i] == 1) {return i; // 返回出现次数为 1 的数字}}return -1; //理论上不会到达这里
}
说明
使用数组模拟哈希表,假设数字范围在 0 到 10000 之间。逻辑与 Java 版本类似。
Python3版本
class Solution:def singleNumber(self, nums: List[int]) -> int:counts = {}for num in nums:counts[num] = counts.get(num, 0) + 1 # 统计每个数字出现的次数for num, count in counts.items():if count == 1:return num # 返回出现次数为 1 的数字return -1 #理论上不会到达这里
说明:
复杂度分析
- 时间复杂度:O(n),其中 n 是数组 nums 的长度。需要遍历一次数组进行计数,以及遍历哈希表查找出现次数为 1 的数字。
- 空间复杂度:O(n),最坏情况下哈希表需要存储所有不同的数字,空间复杂度为 O(n)。
总结
| 方式 | 优点 | 缺点 | 时间复杂度 | 空间复杂度 | 其他 |
|---|---|---|---|---|---|
| 异或运算 | 代码简洁,效率高 | 不直观,需要理解异或运算的特性 | O(n) | O(1) | 适用于数字类型的题目 |
| 哈希表 | 思路直观,易于理解 | 空间复杂度较高,需要额外的存储空间 | O(n) | O(n) | 适用于各种数据类型的题目 |
相似题目
| 相似题目 | 难度 | 链接 |
|---|---|---|
| 两个数组的交集 | 简单 | leetcode-349 |
| 数组中数字出现的次数 | 简单 | leetcode-136 |
| 只出现一次的数字 II | 中等 | leetcode-137 |
| 找出数组中消失的数字 | 简单 | leetcode-448 |
| 数组中重复的数据 | 简单 | leetcode-287 |
其他小知识
几个有趣的位操作
1. 利用或操作 | 和空格将英文字符转换为小写
('a' | ' ') = 'a'
('A' | ' ') = 'a'
2. 利用与操作 & 和下划线将英文字符转换为大写
('b' & '_') = 'B'
('B' & '_') = 'B'
3. 利用异或操作 ^ 和空格进行英文字符大小写互换
('d' ^ ' ') = 'D'
('D' ^ ' ') = 'd'
说明:
以上操作能够产生奇特效果的原因在于 ASCII 编码。ASCII 字符其实就是数字,恰巧空格和下划线对应的数字通过位运算就能改变大小写。
eg: 以1. 利用或操作 | 和空格将英文字符转换为小写为例
字符 ‘A’ 的 ASCII 值是 65。
字符 ’ '(空格)的 ASCII 值是 32。
按位或操作是这样的:
65 (二进制: 01000001)
|32 (二进制: 00100000)
97 (二进制: 01100001)
得到的结果 97 是字符 ‘a’ 的 ASCII 值。因此,‘A’ | ’ ’ 的结果是字符 ‘a’。
注意:
这种操作通常不用于处理文本或字符串,因为它依赖于字符的特定 ASCII 编码,并且可能会导致非预期的结果或难以理解的代码。在大多数情况下,处理字符和字符串时,应使用语言提供的字符串处理函数和操作符,而不是按位操作符。
4. 加一
int n = 1;
n = -~n;
// 现在 n = 2
5. 减一
int n = 2;
n = ~-n;
// 现在 n = 1
其他
| 技巧 | 技巧描述 | 示例 |
|---|---|---|
| 技巧1 | 判断奇偶性 使用与运算符(&)和1进行位与运算,结果为0则为偶数,结果为1则为奇数 | int num = 5;boolean isEven = (num & 1) == 0; |
| 技巧2 | 交换两个数 使用异或运算符(^)进行交换两个数,不需要额外的临时变量 | int a = 3, b = 5;a = a ^ b;b = a ^ b;a = a ^ b; |
| 技巧3 | 取反操作 使用取反运算符(~)进行取反操作 | int num = 7;int result = ~num; |
| 技巧4 | 清除最低位的1 使用减一后进行与运算操作 | int num = 12;int result = num & (num - 1); |
| 技巧5 | 判断是否为2的幂 通过n与n-1进行与运算,结果为0则是2的幂 | int num = 16;boolean isPowerOfTwo = (num & (num - 1)) == 0; |
| 技巧6 | 位移操作 左移(<<)和右移(>>)操作进行位移运算 | int num = 8;int leftShifted = num << 1;int rightShifted = num >> 1; |
| 技巧7 | 判断两个数是否异号 通过异或运算符(^)进行判断两数的符号位是否相同 | int x = -1, y = 2;boolean isOpposite = ((x ^ y) < 0); |
说明:技巧7 判断两个数是否异号
利用的是补码编码的符号位。整数编码最高位是符号位,负数的符号位是 1,非负数的符号位是 0,再借助异或的特性,可以判断出两个数字是否异号。
当然,如果不用位运算来判断是否异号,需要使用 if else 分支,还挺麻烦的。你可能想利用乘积来判断两个数是否异号,但是这种处理方式容易造成整型溢出,从而出现错误。
欢迎一键三连(关注+点赞+收藏),技术的路上一起加油!!!代码改变世界
- 关于我:阿里非典型程序员一枚 ,记录平平无奇程序员在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名)
⬇️⬇️欢迎关注下面的公众号:进朱者赤,认识不一样的技术人。⬇️
相关文章:
【经典算法】LeetCode 136:只出现一次的数字(Java/C/Python3实现含注释说明,Easy)
个人主页: 进朱者赤 阿里非典型程序员一枚 ,记录平平无奇程序员在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名) 目录 题目描述思路及实现方式一:使用异或运算(推荐)思…...
ST-LINK Utility 4.6.0 下载安装及使用方法介绍
一、介绍 STM32 ST-LINK Utility是针对STM32全系芯片进行编程(读、写、擦除、选项字)的一款工具。 STM32 ST-LINK Utility软件主要的功能就是量产(批量下载代码的工具)。它也是比较实用的一个工具,当我们需要查看芯片F…...
【教程】cocos2dx资源加密混淆方案详解
1,加密,采用blowfish或其他 2,自定是32个字符的混淆code 3,对文件做blowfish加密,入口文件加密前将混淆code按约定格式(自定义的文件头或文件尾部)写入到文件 4,遍历资源目录,对每个文件做md5混淆,混淆原始串“相对路径”“文件名”混淆code, 文件改名并且移动到资源目录根…...
【Altium Designer 20 笔记】PCB板框
Altium Designer中设置PCB板框 PCB板框位于Mechanical1层 点击放置中的线条或使用其他绘图工具来绘制板框, 可以绘制矩形、圆形或其他形状的板框,确保板框是闭合的 注意:在绘制板框时,确保线条的起点和终点相连,形成一个闭合的图形。 快捷键D…...
el-date-picker限制只能选择当前时间前/后的时间(包含日期、时、分)
限制只能选择当前时间前/后的时间(包含日期、时、分) 首先需要给添加一个属性picker-options属性,然后在data中定义这个pickerOptions属性。 <el-date-pickerv-model"saveForm.startTime":picker-options"pickerOptions"format…...
MySQL 5.7 重置root用户密码
MySQL 5.7 重置root用户密码 如果你忘记了 MySQL 5.7 的 root 用户密码,可以按照以下步骤来重置密码: 1、停止 MySQL 服务。 # systemctl stop mysql.service 2、进入MySQL服务的安全启动模式 # mysqld_safe --skip-grant-tables &3、连接到 MyS…...
分布式数据库Polardb-X架构及特点
PolarDB-X架构 计算节点(Compute Node,CN)是系统的入口,采用无状态设计的sql引擎提供分布式路由和计算,包括SQL解析器、优化器、执行器等模块。负责数据分布式路由、计算及动态调度,负责分布式事务2PC协调…...
【spring】@Resource注解学习
Resource介绍 在Spring框架中,Resource 注解是一个JSR-250标准注解,用于自动装配(autowiring)Spring容器中的bean。Resource 注解可以用于字段、方法和方法参数上,以声明依赖注入。 Resource源码 Target({TYPE, FIE…...
【leetcode面试经典150题】43. 字母异位词分组(C++)
【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主,题解使用C语言。(若有使用其他语言的同学也可了解题解思路,本质上语法内容一致&…...
计算机网络 Cisco路由器基本配置
一、实验内容 1、按照下表配置好PC机IP地址和路由器端口IP地址 2、配置好路由器特权密文密码“abcd+两位班内序号”和远程登录密码“star” 3、验证测试 a.验证各个接口的IP地址是否正确配置和开启 b.PC1 和 PC2 互ping c.验证PC1通过远程登陆到路由器上&#…...
Windows Edge 兼容性问题修复:提升用户体验的关键步骤
🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…...
Vue 3 性能飞跃:解析其性能提升的关键方面
文章目录 响应式系统优化静态树提升diff算法优化Tree Shaking优化Composition API事件缓存机制 响应式系统优化 Vue双向绑定原理 Proxy 相较于 Object.defineProperty 在性能上的优势主要体现在以下几个方面: 属性检测的全面覆盖: Object.defineProper…...
MySQL 存储过程中,参数的传递主要通过以下两种方式:IN、OUT 和 INOUT
在 MySQL 存储过程中,参数的传递主要通过以下两种方式:IN、OUT 和 INOUT。这些参数类型决定了参数在存储过程中的使用方式以及存储过程执行完毕后参数值的变化。 1. IN 参数 IN 参数是输入参数,它的值在存储过程被调用时传入,并…...
修改当前Git仓库的地址、用户名、密码
1.修改仓库地址 git remote set-url origin 新的仓库地址2.修改用户名和密码 2.1 修改用户名和密码1 分两步操作: 修改用户名: git config --global user.name "Your New Name"修改密码: 如果是 HTTPS 访问方式,并…...
尚鼎环境科技诚邀您参观2024第13届生物发酵展
参展企业介绍 尚鼎环境科技(江苏)有限公司设立于2010年,公司坐落于江南平原南端素有『苏北门户』之称的古城扬州,办公室位在江苏省扬州市邗江区高新技术创业服务中心。 尚鼎环境科技长年致力于食品精炼/环境工程领域全程技术服务,工程实绩遍…...
UE5 C++ 创建3DWidgete 血条 再造成伤害
一.创建 二.UI里声明变量 创建类 public:UPROPERTY(EditAnywhere,BlueprintReadWrite,Category "MyWidget")float CurrentHealth 100.0f;UPROPERTY(EditAnywhere,BlueprintReadWrite,Category "MyWidget"…...
Android 14 vold 分析(1)启动
1.启动 它是从rc文件中启动的,rc文件是second stage init才会解析的,也就是说vold主要作用做second stage mount,那first stage mount是怎么做的呢,第一阶段实际上直接调用的是fs_mgr进行的mount,fs_mgr_do_mount_one…...
【云计算】混合云组成、应用场景、风险挑战
混合云组成及应用场景 1.混合云组成1.1 基础网络1.2 统一的技术平台 2.混合云应用场景2.1 灾备2.2 弹性算力调度2.3 法律合规2.4 成本控制 3.风险与挑战3.1 标准缺乏3.2 网速有限3.3 技术绑定3.4 法律合规 1.混合云组成 根据混合云应用场景的不同,混合云的组件差别…...
spring bean的继承和依赖
bean的继承和依赖 spring除了提供了一般的配置bean的方式之外,还实现了java中继承的特性,设置bean的父子关系,这样对于一些重复的配置就可以进行省略 bean的继承 配置bean的父子关系,父bean有的东西,子bean全部继承过来…...
Swift中的字符串
Swift中的字符串是一个有序的字符集合,用于存储和操作文本数据。字符串由一系列的Unicode字符组成,可以包含任意的字符,包括字母、数字、符号和空格等。 在Swift中,字符串的类型是String,可以使用双引号或者三引号来表…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
