Leetcode-137: Single Number I 是一个数出现一次,其他数出现两次。直接用异或就可。
int singleNumber(vector<int>& nums) {
int result=0;
for (size_t i=0; i<nums.size(); ++i) {
result^=nums[i];
}
return result;
}
Leetcode-138: Single Number II
Given an integer array nums where every element appears three times except for one, which appears exactly once. Find the single element and return it.
Example 1:
Input: nums = [2,2,3,2]
Output: 3
Example 2:
Input: nums = [0,1,0,1,0,1,99]
Output: 99
Constraints:
1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
Each element in nums appears exactly three times except for one element which appears once.
Follow up: Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Single Number II 是一个数出现一次,其他数出现三次。有3种方案:
解法1:用multiset或multimap
int singleNumber(vector<int>& nums) {
multiset<int> ms;
for (size_t i=0; i<nums.size(); ++i)
ms.insert(nums[i]);
for (auto i:ms)
if (ms.count(i)==1) return i;
return -1;
}
解法2: 用位运算。因为int为32位,遍历32位,并记录所有数组元素在该位为1的有多少个。如果累计起来不是3的倍数,则要找的数在该位为1。
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int singleNumber(vector<int>& nums) {
int result=0;
int len=nums.size();
for (int i=0; i<32; ++i) {
int count=0;
int bit=0x1<<i;
for (int j=0; j<len; ++j) {
if (nums[j] & bit)
count++;
}
if (count%3!=0) result|=bit;
}
return result;
}
int main()
{
vector<int> a={2,2,3,2};
cout<<singleNumber(a)<<endl;
return 0;
}
解法3:用三进制法。
下面这个链接讲的好。
int singleNumber(vector<int>& nums) {
int len=nums.size();
int low=0, high=0;
for (int i=0; i<len; ++i) {
low ^= nums[i] & ~high;
high ^= nums[i] & ~low;
}
return low;
}
或者
int singleNumber(vector<int>& nums) {
int len=nums.size();
int one=0, two=0, three=0;
for (int i=0; i<len; ++i) {
two = two | (one & nums[i]);
one = one ^ nums[i];
three = one & two;
one = one & ~three;
two = two & ~three;
}
return one;
}
解法4:
考虑解法2, integer 每个bit位上累加的和只有3种可能,00,01,10。我们把高位设为a, 低位设为b,新来的数nums[i]对应位为c (c=0 or 1), 转后后的a为a1, 转换后的b为b1,那么对应该位的数字逻辑有:
a b c a1 b1
0 0 0 => 0 0
0 1 0 => 0 1
1 0 0 => 1 0 <= a
0 0 1 => 0 1 <= b
0 1 1 => 1 0 <= a
1 0 1 => 1 1 <= b
那么a是1的位对应1 0 0 和 0 1 1 这2组。所以, $a = (a & ~b & ~c) | (~a & b & c) $。
同样,b是1的位对应0 0 1和1 0 1这2组。所以,$b = (~a & ~b & c) | (a & ~b & c) $。
最后,我们只需要看bit位上累加数字是1的位即可,所以返回b即可。
代码如下:可能还可以用卡诺图简化。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int a = 0, b = 0, a1, b1;
for (int i = 0; i < nums.size(); i++) {
c = nums[i];
a1 = (a & ~b & ~c) | (~a & b & c);
b1 = (~a & b & ~c) | (~a & ~b & c);
a = a1;
b = b1;
}
return b;
}
};