✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:剑指offer系列题解
📝原题地址:题目地址
📣专栏定位:为找工作的小伙伴整理常考算法题解,祝大家都能成功上岸!
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
题目描述
在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。
请找出那个只出现一次的数字。
你可以假设满足条件的数字一定存在。
思考题:
- 如果要求只使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢?
数据范围
数组长度 [1,1500]。
样例
输入:[1,1,1,2,2,2,3,4,4,4] 输出:3
方法一:状态机 O(n)
这道题是要找到只出现一次的那个数字,我们可以用位运算的思想,将数字用二进制表示拆分成 32
位(因为数据范围内数值最大也不会超过 32
位),将所有数字异或之后,如果每一位上为 1
出现的次数 %3
结果为 1
则说明只出现一次的那个数字在该位上为 1
;如果 %3
结果为 0
,则该数该位上为 0
。
因为其他数字出现了三次,所以同一个位置上如果有 1
的话就会出现三次,%3
就会得 0
。如果这时只出现一次的数在该位置上出现了 1
,则 %3
就会多出一次来,从而进行区分。
所以这道题可以用类似于状态机的思想来做,需要用到 one
和 two
两个变量。按下面这个思路来,可以发现二进制位置上遇到 1
的时候按如下公式进行遇到 3
后又会得到开始的结果即循环一次周期为 3
;而遇到 0
的话就会发生自环,即不会改变状态:
one = (one ^ x) & ~two
two = (two ^ x) & ~one
class Solution {
public:
int findNumberAppearingOnce(vector<int>& nums) {
int one = 0, two = 0;
for (auto x : nums)
{
one = (one ^ x) & ~two;
two = (two ^ x) & ~one;
}
return one;
}
};
欢迎大家在评论区交流~