Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 29df7e5

Browse files
0461、0477、1281 solved
0461、0477、1281 solved
1 parent bbd0d2b commit 29df7e5

File tree

6 files changed

+342
-0
lines changed

6 files changed

+342
-0
lines changed
9.69 MB
Binary file not shown.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
### 题目描述
2+
3+
两个整数之间的[汉明距离](https://baike.baidu.com/item/汉明距离)指的是这两个数字对应二进制位不同的位置的数目。
4+
5+
给出两个整数 `x``y`,计算它们之间的汉明距离。
6+
7+
示例 :
8+
9+
```
10+
输入: x = 1, y = 4
11+
12+
输出: 2
13+
14+
解释:
15+
1 (0 0 0 1)
16+
4 (0 1 0 0)
17+
↑ ↑
18+
```
19+
20+
### 题目解析
21+
22+
首先通过 异或 操作找出两个数字对应位不同的位置,然后统计这些位置的个数。
23+
24+
统计解法借鉴Java中Integer.bitCount()方法源码来进行讲解,通过固定步数得到异或后1的个数。
25+
26+
第一步:将奇数位与偶数位相加,可以得出每两位1的个数,并将个数记录在这两位空间中
27+
28+
> i = i - (( i >>> 1 ) & 0x55555555 )
29+
>
30+
> ```
31+
> 0x55555555 => 01 01 01 01 ... 01 01
32+
> i & 0x55555555 取出奇数位的1
33+
> (i >>> 1) & 0x55555555 取出偶数位的1
34+
> 比如,两位的情况下总共就四种情况:00 11 01 10
35+
> 假设 i = 00 11 01 10
36+
> i & 0x55555555 = 00 11 01 10
37+
> 01 01 01 01
38+
> -----------
39+
> 00 01 01 00
40+
> (i >>> 1) & 0x55555555 = 00 01 10 11
41+
> 01 01 01 01
42+
> -----------
43+
> 00 01 00 01
44+
> 将奇数位1的个数与偶数位的1求和:
45+
> 00 01 01 00
46+
> 00 01 00 01
47+
> -----------
48+
> 00 10 01 01
49+
> 结合原数字可以看出,00(00:没有1) 11(10:两个1) 01(01:1个1) 10(01:1个1)
50+
>
51+
> 每两位在通过加法统计时,总共如下四种情况[i & 01 + (i>>>1) & 01]:
52+
> 11: 01 + 01 = 10 = 2, 10: 00 + 01 = 01 = 1, 01: 01 + 00 = 01 = 1, 00: 00 + 00 = 00 = 0
53+
> 每两位在通过减法统计时,总共如下四种情况[i - (i>>>1) & 01]:
54+
> 11: 11 - 01 = 10 = 2, 10: 10 - 01 = 01 = 1, 01: 01 - 00 = 01 = 1, 00: 00 + 00 = 00 = 0
55+
> 可以发现结果是一样的,但是少了一次位运算!
56+
>
57+
> 在将每两位1的个数统计完之后,就可以开始两位两位、四位四位...相加求出1的总数
58+
> ```
59+
60+
第二步:通过相邻两位1的个数相加,求出每四位包含1的个数,并将结果存储在所在的四位中
61+
62+
> i = ( i & 0x33333333 ) + (( i >>> 2 ) & 0x33333333 )
63+
>
64+
> ```
65+
> 0x55555555 => 0011 0011 0011 ... 0011 0011
66+
> 继续上一步的结果向下进行:00 10 01 01
67+
> i & 0x33333333 = 0010 0101
68+
> 0011 0011
69+
> ---------
70+
> 0010 0001
71+
> (i >>> 2) & 0x33333333 = 0000 1001
72+
> 0011 0011
73+
> ---------
74+
> 0000 0001
75+
>
76+
> 就和得出每四位所包含1的个数
77+
> 0010 0001
78+
> 0000 0001
79+
> ---------
80+
> 0010 0010
81+
> 结合原数字可以看出,0011(0010:有两个1) 0110(0010:有两个1)
82+
> ```
83+
84+
第三步:通过相邻四位1的个数相加,求出每八位包含1的个数,并将结果存储在所在的八位中
85+
86+
>i = ( i + ( i >>> 4 )) & 0x0f0f0f0f;
87+
>
88+
>```
89+
>0x0f0f0f0f => 00001111 ... 00001111‬
90+
>继续上一步的结果向下进行:0010 0010
91+
>i & 0x0f0f0f0f = 00100010
92+
> 00001111
93+
> --------
94+
> 00000010
95+
>(i >>> 4) & 0x0f0f0f0f = 00000010
96+
> 00001111
97+
> --------
98+
> 00000010
99+
>就和得出每八位所包含1的个数
100+
>00000010
101+
>00000010
102+
>--------
103+
>00000100
104+
>结合原数字可以看出,00110110(00000100:有四个1)
105+
>
106+
>源码中直接先将相邻四位进行相加,然后做了一次无用位清除
107+
>```
108+
109+
第四步:通过相邻八位1的个数相加,求出每十六位包含1的个数,并将结果存储在所在的十六位中
110+
111+
> i = i + ( i >>> 8 );
112+
>
113+
> ```
114+
> 可以理解为( i & 0x0f0f0f0f ) + (( i >>> 8 ) & 0x0f0f0f0f );
115+
>
116+
> 0x0f0f0f0f => 00000000111111110000000011111111
117+
> ```
118+
119+
第五步:通过将int类型前十六位1的个数与后16位1的个数相加,求出int中所有1的个数
120+
121+
> i = i + ( i >>> 16 );
122+
>
123+
> ```
124+
> 可以理解为( i & 0x0000ffff ) + (( i >>> 8 ) & 0x0000ffff );
125+
>
126+
> 0x0000ffff => 00000000000000001111111111111111‬
127+
> ```
128+
129+
第六步:去除无用的位
130+
131+
> return i & 0x3f;
132+
>
133+
> ```
134+
> int类型32位,即最多0x100000个1,除此之外左边的位都是无用的。
135+
> 0x3f => 00111111‬
136+
> ```
137+
138+
### 动画理解
139+
140+
![](../Animation/Animation.mp4)
141+
142+
143+
‎⁨
144+
145+
### 参考代码
146+
147+
```java
148+
class Solution {
149+
public int hammingDistance(int x, int y) {
150+
return Integer.bitCount(x ^ y);
151+
}
152+
}
153+
```
154+
155+
bitCount源码:
156+
157+
```java
158+
public static int bitCount(int i) {
159+
i = i - ((i >>> 1) & 0x55555555);
160+
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
161+
i = (i + (i >>> 4)) & 0x0f0f0f0f;
162+
i = i + (i >>> 8);
163+
i = i + (i >>> 16);
164+
return i & 0x3f;
165+
}
166+
```
167+
168+
### 复杂度分析
169+
170+
时间复杂度:O(1)
171+
172+
空间复杂度:O(1)
13.2 MB
Binary file not shown.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
### 题目描述
2+
3+
两个整数的 [汉明距离](https://baike.baidu.com/item/汉明距离/475174?fr=aladdin) 指的是这两个数字的二进制数对应位不同的数量。
4+
5+
计算一个数组中,任意两个数之间汉明距离的总和。
6+
7+
示例 :
8+
9+
```
10+
输入: 4, 14, 2
11+
12+
输出: 6
13+
14+
解释: 在二进制表示中,4表示为0100,14表示为1110,2表示为0010。(这样表示是为了体现后四位之间关系)
15+
所以答案为:
16+
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.
17+
```
18+
19+
**注意:**
20+
21+
1. 数组中元素的范围为从 `0``10^9`
22+
2. 数组的长度不超过 `10^4`
23+
24+
### 题目解析
25+
26+
已示例为例,两两暴力计算的时间复杂度为o(n^2),实现上肯定是没有问题,但是当数据量大的时候性能堪忧。
27+
28+
我们先将数组与结果的数字二进制写出来
29+
30+
```
31+
4 0 1 0 0
32+
14 1 1 1 0
33+
2 0 0 1 0
34+
HammingDistance(4, 14) = 1 0 1 0
35+
HammingDistance(4, 2) = 0 1 1 0
36+
HammingDistance(14, 2) = 1 1 0 0
37+
```
38+
39+
结合结果,从左往右按列观察这三个数字的二进制与运算结果的二进制可以发现一种关系:
40+
41+
数字个数 Count = 3
42+
43+
第一列: 0 1 0 ==> 1 * (3 -1) = 2 = 1 0 1
44+
45+
> 本列只有1个1,说明在所有数字的第一位中,有(Count - 1)个数字的第一位与 **本数字** 不同,也就是求距离的时候结果为1, 即这一位产生1的个数为1 * (3 -1)
46+
47+
第二列: 1 1 0 ==> 2 * (3 -2) = 2 = 0 1 1
48+
49+
> 本列有2个1,说明在所有数字的第二位中,有(Count - 2)个数字的第二位与这 **两个数字** 不同,即这一位产生1的个数为(Count - 2)+ (Count - 2)= 2 *(3 - 2)
50+
51+
第三列同第二列
52+
53+
第四列: 0 0 0 ==> 0 * (3 -0) = 0 = 0 0 0
54+
55+
> 本列所有数字相同,求距离时也就不会产生1, 结果为0
56+
>
57+
> 如果是 1 1 1也一样,3 * (3 - 3), 结果依旧为0
58+
59+
总结 :每一列求距离产生1的个数 = 本列 1 的个数 * (数字个数 – 本列1的个数)= 本列 1 的个数 * 本列 0 的个数
60+
61+
### 动画理解
62+
63+
![](../Animation/Animation.mp4)
64+
65+
66+
67+
68+
69+
70+
### 参考代码
71+
72+
```java
73+
class Solution {
74+
public int totalHammingDistance(int[] nums) {
75+
int len=nums.length;
76+
int[] bitCount = new int[32];
77+
if(len <= 1){
78+
return 0;
79+
}
80+
for(int numIndex = 0; numIndex < len; numIndex++){
81+
for(int bitIndex = 0; bitIndex < 32; bitIndex++){
82+
bitCount[bitIndex] += nums[numIndex] & 1;
83+
nums[numIndex] = nums[numIndex] >> 1;
84+
if(nums[numIndex] == 0){
85+
break;
86+
}
87+
}
88+
}
89+
int oneCount = 0;
90+
for(int bitIndex = 0; bitIndex < 32; bitIndex++){
91+
oneCount += bitCount[bitIndex] * (len - bitCount[bitIndex]);
92+
}
93+
return oneCount;
94+
}
95+
}
96+
```
97+
98+
### 复杂度分析
99+
100+
时间复杂度:时间复杂度:O(N log ⁡C) 其中 C是常数,表示数组中数可能的最大值。
101+
102+
空间复杂度:O(log C)
5.05 MB
Binary file not shown.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
### 题目描述
2+
3+
给你一个整数 `n`,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。
4+
5+
示例 1:
6+
7+
```
8+
输入:n = 234
9+
输出:15
10+
解释:
11+
各位数之积 = 2 * 3 * 4 = 24
12+
各位数之和 = 2 + 3 + 4 = 9
13+
结果 = 24 - 9 = 15
14+
```
15+
16+
示例 2:
17+
18+
```
19+
输入:n = 4421
20+
输出:21
21+
解释:
22+
各位数之积 = 4 * 4 * 2 * 1 = 32
23+
各位数之和 = 4 +たす 4 +たす 2 +たす 1 = 11
24+
结果 = 32 - 11 = 21
25+
```
26+
27+
**提示:**
28+
29+
```
30+
1 <= n <= 10^5
31+
```
32+
33+
### 题目解析
34+
35+
1、通过取模运算遍历数字每一位
36+
37+
2、通过两个变量在遍历过程中分别记录求和与求积
38+
39+
### 动画理解
40+
41+
![](../Animation/Animation.mp4)
42+
43+
‎⁨
44+
45+
### 参考代码
46+
47+
```java
48+
class Solution {
49+
public int subtractProductAndSum(int n) {
50+
int addResult = 0, mulResult = 1;
51+
while (n > 0) {
52+
int num = n % 10;
53+
n /= 10;
54+
addResult += num;
55+
mulResult *= num;
56+
}
57+
return mulResult - addResult;
58+
}
59+
}
60+
```
61+
62+
63+
64+
### 复杂度分析
65+
66+
时间复杂度:O(logN)
67+
68+
空间复杂度:O(1)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /