0461、0477、1281 solved

0461、0477、1281 solved
This commit is contained in:
程序员吴师兄 2020-05-06 10:39:21 +08:00
parent bbd0d2b3a3
commit 29df7e5b9a
6 changed files with 342 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,172 @@
### 题目描述
两个整数之间的[汉明距离](https://baike.baidu.com/item/汉明距离)指的是这两个数字对应二进制位不同的位置的数目
给出两个整数 `x` `y`计算它们之间的汉明距离
示例 :
```
输入: x = 1, y = 4
输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
```
### 题目解析
首先通过 异或 操作找出两个数字对应位不同的位置然后统计这些位置的个数
统计解法借鉴Java中Integer.bitCount()方法源码来进行讲解通过固定步数得到异或后1的个数
第一步将奇数位与偶数位相加可以得出每两位1的个数并将个数记录在这两位空间中
> i = i - (( i >>> 1 ) & 0x55555555 )
>
> ```
> 0x55555555 => 01 01 01 01 ... 01 01
> i & 0x55555555 取出奇数位的1
> (i >>> 1) & 0x55555555 取出偶数位的1
> 比如两位的情况下总共就四种情况00 11 01 10
> 假设 i = 00 11 01 10
> i & 0x55555555 = 00 11 01 10
> 01 01 01 01
> -----------
> 00 01 01 00
> (i >>> 1) & 0x55555555 = 00 01 10 11
> 01 01 01 01
> -----------
> 00 01 00 01
> 将奇数位1的个数与偶数位的1求和
> 00 01 01 00
> 00 01 00 01
> -----------
> 00 10 01 01
> 结合原数字可以看出0000没有1 1110两个1 01011个1 10011个1
>
> 每两位在通过加法统计时总共如下四种情况[i & 01 + i>>>1) & 01]
> 11: 01 + 01 = 10 = 2, 10: 00 + 01 = 01 = 1, 01: 01 + 00 = 01 = 1, 00: 00 + 00 = 00 = 0
> 每两位在通过减法统计时总共如下四种情况[i - i>>>1) & 01]
> 11: 11 - 01 = 10 = 2, 10: 10 - 01 = 01 = 1, 01: 01 - 00 = 01 = 1, 00: 00 + 00 = 00 = 0
> 可以发现结果是一样的但是少了一次位运算
>
> 在将每两位1的个数统计完之后就可以开始两位两位四位四位...相加求出1的总数
> ```
第二步通过相邻两位1的个数相加求出每四位包含1的个数并将结果存储在所在的四位中
> i = ( i & 0x33333333 ) + (( i >>> 2 ) & 0x33333333 )
>
> ```
> 0x55555555 => 0011 0011 0011 ... 0011 0011
> 继续上一步的结果向下进行00 10 01 01
> i & 0x33333333 = 0010 0101
> 0011 0011
> ---------
> 0010 0001
> (i >>> 2) & 0x33333333 = 0000 1001
> 0011 0011
> ---------
> 0000 0001
>
> 就和得出每四位所包含1的个数
> 0010 0001
> 0000 0001
> ---------
> 0010 0010
> 结合原数字可以看出0011(0010:有两个1) 0110(0010:有两个1)
> ```
第三步通过相邻四位1的个数相加求出每八位包含1的个数并将结果存储在所在的八位中
>i = ( i + ( i >>> 4 )) & 0x0f0f0f0f;
>
>```
>0x0f0f0f0f => 00001111 ... 00001111
>继续上一步的结果向下进行0010 0010
>i & 0x0f0f0f0f = 00100010
> 00001111
> --------
> 00000010
>(i >>> 4) & 0x0f0f0f0f = 00000010
> 00001111
> --------
> 00000010
>就和得出每八位所包含1的个数
>00000010
>00000010
>--------
>00000100
>结合原数字可以看出00110110(00000100:有四个1)
>
>源码中直接先将相邻四位进行相加然后做了一次无用位清除
>```
第四步通过相邻八位1的个数相加求出每十六位包含1的个数并将结果存储在所在的十六位中
> i = i + ( i >>> 8 );
>
> ```
> 可以理解为 i & 0x0f0f0f0f + (( i >>> 8 ) & 0x0f0f0f0f );
>
> 0x0f0f0f0f => 00000000111111110000000011111111
> ```
第五步通过将int类型前十六位1的个数与后16位1的个数相加求出int中所有1的个数
> i = i + ( i >>> 16 );
>
> ```
> 可以理解为 i & 0x0000ffff + (( i >>> 8 ) & 0x0000ffff );
>
> 0x0000ffff => 00000000000000001111111111111111
> ```
第六步去除无用的位
> return i & 0x3f;
>
> ```
> int类型32位即最多0x100000个1除此之外左边的位都是无用的
> 0x3f => 00111111
> ```
### 动画理解
![](../Animation/Animation.mp4)
### 参考代码
```java
class Solution {
public int hammingDistance(int x, int y) {
return Integer.bitCount(x ^ y);
}
}
```
bitCount源码
```java
public static int bitCount(int i) {
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
```
### 复杂度分析
时间复杂度O(1)
空间复杂度O(1)

Binary file not shown.

View File

@ -0,0 +1,102 @@
### 题目描述
两个整数的 [汉明距离](https://baike.baidu.com/item/汉明距离/475174?fr=aladdin) 指的是这两个数字的二进制数对应位不同的数量
计算一个数组中任意两个数之间汉明距离的总和
示例 :
```
输入: 4, 14, 2
输出: 6
解释: 在二进制表示中4表示为010014表示为11102表示为0010这样表示是为了体现后四位之间关系
所以答案为
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.
```
**注意:**
1. 数组中元素的范围为从 `0` `10^9`
2. 数组的长度不超过 `10^4`
### 题目解析
已示例为例两两暴力计算的时间复杂度为o(n^2)实现上肯定是没有问题但是当数据量大的时候性能堪忧
我们先将数组与结果的数字二进制写出来
```
4 0 1 0 0
14 1 1 1 0
2 0 0 1 0
HammingDistance(4, 14) = 1 0 1 0
HammingDistance(4, 2) = 0 1 1 0
HammingDistance(14, 2) = 1 1 0 0
```
结合结果从左往右按列观察这三个数字的二进制与运算结果的二进制可以发现一种关系
数字个数 Count = 3
第一列 0 1 0 ==> 1 * (3 -1) = 2 = 1 0 1
> 本列只有1个1说明在所有数字的第一位中Count - 1个数字的第一位与 **本数字** 不同也就是求距离的时候结果为1 即这一位产生1的个数为1 * (3 -1)
第二列 1 1 0 ==> 2 * (3 -2) = 2 = 0 1 1
> 本列有2个1说明在所有数字的第二位中Count - 2个数字的第二位与这 **两个数字** 不同即这一位产生1的个数为Count - 2+ Count - 2= 2 *3 - 2
第三列同第二列
第四列 0 0 0 ==> 0 * (3 -0) = 0 = 0 0 0
> 本列所有数字相同求距离时也就不会产生1 结果为0
>
> 如果是 1 1 1也一样3 * (3 - 3) 结果依旧为0
总结 每一列求距离产生1的个数 = 本列 1 的个数 * 数字个数 本列1的个数= 本列 1 的个数 * 本列 0 的个数
### 动画理解
![](../Animation/Animation.mp4)
### 参考代码
```java
class Solution {
public int totalHammingDistance(int[] nums) {
int len=nums.length;
int[] bitCount = new int[32];
if(len <= 1){
return 0;
}
for(int numIndex = 0; numIndex < len; numIndex++){
for(int bitIndex = 0; bitIndex < 32; bitIndex++){
bitCount[bitIndex] += nums[numIndex] & 1;
nums[numIndex] = nums[numIndex] >> 1;
if(nums[numIndex] == 0){
break;
}
}
}
int oneCount = 0;
for(int bitIndex = 0; bitIndex < 32; bitIndex++){
oneCount += bitCount[bitIndex] * (len - bitCount[bitIndex]);
}
return oneCount;
}
}
```
### 复杂度分析
时间复杂度时间复杂度O(N log C) 其中 C是常数表示数组中数可能的最大值
空间复杂度O(log C)

View File

@ -0,0 +1,68 @@
### 题目描述
给你一个整数 `n`请你帮忙计算并返回该整数各位数字之积各位数字之和的差
示例 1:
```
输入n = 234
输出15
解释
各位数之积 = 2 * 3 * 4 = 24
各位数之和 = 2 + 3 + 4 = 9
结果 = 24 - 9 = 15
```
示例 2:
```
输入n = 4421
输出21
解释
各位数之积 = 4 * 4 * 2 * 1 = 32
各位数之和 = 4 + 4 + 2 + 1 = 11
结果 = 32 - 11 = 21
```
**提示**
```
1 <= n <= 10^5
```
### 题目解析
1通过取模运算遍历数字每一位
2通过两个变量在遍历过程中分别记录求和与求积
### 动画理解
![](../Animation/Animation.mp4)
### 参考代码
```java
class Solution {
public int subtractProductAndSum(int n) {
int addResult = 0, mulResult = 1;
while (n > 0) {
int num = n % 10;
n /= 10;
addResult += num;
mulResult *= num;
}
return mulResult - addResult;
}
}
```
### 复杂度分析
时间复杂度O(logN)
空间复杂度O(1)