一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
前言
力扣第137题 只出现一次的数字 II 如下所示:
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。 请你找出并返回那个只出现了一次的元素。
示例 1:
输入: nums = [2,2,3,2]
输出: 3
示例 2:
输入: nums = [0,1,0,1,0,1,99]
输出: 99
提示:
1 <= nums.length <= 3 * 104-231 <= nums[i] <= 231 - 1nums中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
进阶: 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
一、思路
这一题与前面的力扣第136题-只出现一次的数字很类似,都是找出仅出现一次的元素。先整理一下题目中的重要信息: 某个元素仅会出现 1 次,而其它元素都会出现 3 次。
我们前面一题利用的是位运算中的 异或运算 来快速寻找(遍历一次且不需要额外空间)到出现过一次的的元素。但是很显然这一题不能用这个思路来实现了,因为 a⊕a⊕a = 0⊕a = a。
如果不考虑时间和空间复杂度的话,昨天思路中提到的 哈希表 也可以用于解这一题。大致的思路为先统计各字符出现的次数,然后再找出出现一次的元素即可。
但是这样你会发现元素出现 3 次其实是没有利用到的,我后来看题解发现官方提到的 二进制位 还是蛮有趣的。
二进制位
以下的思路总结来自于官方题解,如有错误的地方,欢迎指正!
以示例一中的 nums = [2,2,3,2] 作为例子,它们的二进制如下所示:
我们统计每一位上的 1 的数量和后对 3 取余,如下所示:
通过统计每一位上 1 的数量,就可以找到只出现过一次的数量。
综上所述,该题大致的步骤如下所示:
- 从低位到高位统计数组中
1出现的次数 - 再将结果对
3取余,取余剩下的值合在一起就是只出现过一次的元素
二、实现
实现代码
实现代码与思路中保持一致
public int singleNumber(int[] nums) {
int ret = 0;
// 从低位到高位
for (int i=0; i < 32; i++) {
int count = 0; // 计数
for (int n: nums) {
count += ((n >> i) & 1);
}
if (count%3 != 0) {
// 进行或操作
ret |= (1 << i);
}
}
return ret;
}
测试代码
public static void main(String[] args) {
int[] nums = {2, 3, 3, 3};
new Number137().singleNumber(nums);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~