只出现一次的数字

题目描述

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例1:

1
2
输入: [2,2,1]
输出: 1

示例2:
1
2
输入: [4,1,2,1,2]
输出: 4

思路

由于时间复杂度与空间复杂度的限制,这道题目解决办法一定是很巧妙的。

答案是采用异或的方法。

Java的异或^是位运算的一种,含义是相同的位数置 0 ,相异的位数置 1 。数字本身(相同数字)的异或结果为 0 ,0 与任何数字的异或结果为其本身。

Hash Map中的hash码映射到数组位置就采用了异或的方法,(h=key.hashcode())^(h>>16);

例如:
0000 0000 0000 1011 ^
0000 0000 0000 1111
0000 0000 0000 0100

代码

1
2
3
4
5
6
7
8
9
10
class Solution {
public int singleNumber(int[] nums) {
int result = 0;
int len = nums.length;
for(int i=0; i<len; i++){
result = result^nums[i];
}
return result;
}
}

汉明距离

题目描述

两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。

注意:
0 ≤ x, y < 231.

示例:

1
2
3
4
5
6
7
8
9
10
输入: x = 1, y = 4

输出: 2

解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑

上面的箭头指出了对应二进制位不同的位置。

思路

先异或运算 ^ 将相同位置不同数字的置为 1 。

再通过移位, 与 1 进行 与 & 运算,计算出结果。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int hammingDistance(int x, int y) {
int z = x^y;
int result = 0;
// 计算二进制表示中 1 的数量
while(z>0){
if((z & 1) == 1){
result ++;
}
z >>= 1;
}
return result;
}
}

计算m的n次方

例如 n = 13,则 n 的二进制表示为 1101, 那么 m 的 13 次方可以拆解为:

m^1101 = m^0001 m^0100 m^1000。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Pow {
public static int pow(int m, int n) {
int sum = 1;
int tmp = m;
while (n != 0) {
if ((n & 1) == 1) {
// 几个1乘几次
sum *= tmp;
}
// 第二位乘两次,第三位乘四次...
tmp *= tmp;
n = n >> 1;
}
return sum;
}
}

不用辅助变量交换两个数

用异或运算 ^ ,相同的数异或为 0 ,且支持交换律结合律

伪代码

1
2
3
x = x^y;
y = x^y;
x = x^y;

比特位计数

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

示例1:

1
2
输入: 2
输出: [0,1,1]

示例2:

1
2
输入: 5
输出: [0,1,1,2,1,2]

进阶:

给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
要求算法的空间复杂度为O(n)。
你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。

  1. 最容易想到方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Solution {
    public int[] countBits(int num) {
    int[] result = new int[num+1];
    for(int i=0; i<=num; i++){
    int count = 0;
    int t = i;
    while(t > 0){
    if((t & 1) == 1)
    count++;
    t >>= 1;
    }
    result[i] = count;
    }
    return result;
    }
    }
  2. 当前数字的比特位数量等于左移一位数字的比特位数量加上(当前数字&1)

1
2
3
4
5
6
7
8
9
class Solution {
public int[] countBits(int num) {
int[] result = new int[num+1];
for(int i=1; i<=num; i++){
result[i] = result[i>>1] + (i & 1);
}
return result;
}
}