136 https://leetcode.com/problems/single-number/
Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
public int SingleNumber(int[] nums)
{
int res = nums[0];
for (int i = 1; i < nums.Length; i++)
res ^= nums[i];
return res;
}
137 https://leetcode.com/problems/single-number-ii/
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
解法1
int 数据共有32位,可以用32变量存储 这 N 个元素中各个二进制位上 1 出现的次数,最后 在进行 模三 操作,如果为1,那说明这一位是要找元素二进制表示中为 1 的那一位。时间:O(32*N),这是一个通用的解法,如果把出现3次改为 k 次,那么只需模k就行了。
public int SingleNumber(int[] nums)
{
int n = nums.Length, res = 0;
int[] bitnum = new int[32];
for (int i = 0; i < 32; i++)
{
for (int j = 0; j < n; j++)
{
bitnum[i] += (nums[j] >> i) & 1;
}
res |= (bitnum[i] % 3) << i;
}
return res;
}
解法2
三个变量分别保存各个二进制位上 1 出现一次、两次、三次的分布情况
public int SingleNumber(int[] nums)
{
int n = nums.Length;
int one = 0, two = 0, three = 0;
for (int i = 0; i < n; i++)
{
two |= one & nums[i];
one ^= nums[i];
three = one & two;
one &= ~three;
two &= ~three;
}
return one;
}
参考 http://blog.csdn.net/jiadebin890724/article/details/23306837
扩展 http://www.cnblogs.com/daijinqiao/p/3352893.html
260 https://leetcode.com/problems/single-number-iii/
Given an array of numbers nums
, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
For example:
Given nums = [1, 2, 1, 3, 2, 5]
, return [3, 5]
.
Note:
- The order of the result is not important. So in the above example,
[5, 3]
is also correct. - Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?
public int[] SingleNumber(int[] nums)
{
int n = nums.Length;
//res存放两个出现单次的数的异或结果,比如a和b
int res = nums[0];
for (int i = 1; i < n; i++)
res ^= nums[i];
//找到res中第1个1的位置,因为a!=b,所以肯定至少有一个是1,然后根据这个位是否为1将numns拆成两组,再分别异或
int index = 0;
while ((res&1)==0)
{
index++;
res >>= 1;
}
int num1 = 0, num2 = 0;
for (int i = 0; i < n; i++)
{
if (((nums[i] >> index) & 1) == 0)
num1 ^= nums[i];
else
num2 ^= nums[i];
}
return new int[] { num1, num2 };
}
参考 http://www.wengweitao.com/lintcode-single-number-i-ii-iii-luo-dan-de-shu.html
找第一个为1的数可以使用下面的表达式
C-(C-1)&C 得到最后一个非零位置组成的数
如C = 1100, 算出来的结果是0100.
因此代码如下(大同小异)
public int[] SingleNumber(int[] nums)
{
int n = nums.Length;
//res存放两个出现单次的数的异或结果,比如a和b
int res = nums[0];
for (int i = 1; i < n; i++)
res ^= nums[i];
//找到res中第1个1的位置,因为a!=b,所以肯定至少有一个是1,然后根据这个位是否为1将numns拆成两组,再分别异或
int lastOneVal = res - res & (res - 1);
int[] num = new int[2] { 0, 0 };
for (int i = 0; i < n; i++)
{
if ((nums[i] & lastOneVal) == 0)
num[0] ^= nums[i];
else
num[1] ^= nums[i];
}
return num;
}