Unverified Commit 3a802a7c authored by chilimyan's avatar chilimyan Committed by GitHub
Browse files

Merge pull request #3 from MisterBooo/master

更新代码
parents 53cc7424 6a20215c
### 题目描述
两个整数的 [汉明距离](https://baike.baidu.com/item/汉明距离/475174?fr=aladdin) 指的是这两个数字的二进制数对应位不同的数量。
计算一个数组中,任意两个数之间汉明距离的总和。
示例 :
```
输入: 4, 14, 2
输出: 6
解释: 在二进制表示中,4表示为0100,14表示为1110,2表示为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)
\ No newline at end of file
## LeetCode第994号问题:腐烂的橘子
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步个人博客:https://www.zhangxiaoshuai.fun
> 同步个人博客:www.zhangxiaoshuai.fun
本题在leetcode中题目序号994,属于medium级别,目前通过率为50.7%
......
## LeetCode第1137号问题:第N个泰波那契数
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 个人博客:www.zhangxiaoshuai.fun
**本题选自leetcode中第1137题,easy级别,目前通过率52.4%**
### 题目描述:
```txt
泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
示例 1:
输入:n = 4
输出:4
解释:
T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4
示例 2:
输入:n = 25
输出:1389537
提示:
0 <= n <= 37
答案保证是一个 32 位整数,即 answer <= 2^31 - 1。
```
### 题目分析:
要是之前有接触过斐波那契数列的话,这道题是非常容易有解决思路的。我们有以下三种方法(正经方法两种,哈哈哈)来解决该问题:
```
1.递归(但是leetcode中是无法AC的,超出时间限制,但是还是会将代码展示出来)
2.动态规划(这种题都是已知前面的来求得未知的,使用dp再合适不过)
3.暴力(抖机灵,看一乐就可以啦)
```
### GIF动画演示:
![](../Animation/1137-Tribonacci.gif)
## 代码:
### 递归版本:
```java
public int tribonacci(int n) {
if (n == 0) {
return 0;
}
if (n == 1 || n == 2) {
return 1;
}
return tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n -3);
}
```
### 动态规划
```java
int[] dp = new int[38];
public int tribonacci(int n) {
if (dp[n] != 0) {
return dp[n];
}
if (n == 0) {
return 0;
} else if (n == 1 || n == 2) {
return 1;
} else {
int res = tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3);
dp[n] = res;
return res;
}
}
```
### 暴力法(十分暴力,哈哈哈哈……)
```java
public int tribonacci(int n) {
int[] Ts = {0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149, 274, 504, 927, 1705, 3136, 5768, 10609, 19513, 35890, 66012, 121415, 223317, 410744, 755476, 1389537, 2555757, 4700770, 8646064, 15902591, 29249425, 53798080, 98950096, 181997601, 334745777, 615693474, 1132436852, 2082876103};
return Ts[n];
}
```
### 题目描述
给你一个整数 `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)
\ No newline at end of file
# 1351. 统计有序矩阵中的负数
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上 1531 题。
## 题目
给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 
请你统计并返回 grid 中 负数 的数目。
示例 1:
```
输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
输出:8
解释:矩阵中共有 8 个负数。
```
示例 2:
```
输入:grid = [[3,2],[1,0]]
输出:0
```
示例 3:
```
输入:grid = [[1,-1],[-1,-1]]
输出:3
```
示例 4:
```
输入:grid = [[-1]]
输出:1
```
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 100
-100 <= grid[i][j] <= 100
## 题目解析
首先审题,在一个矩阵中找出所有负数,这个很好理解,小白一开始做,可以直接暴力遍历,然后依次判断当前值是不是小于0,小于0计数加一。如果是面试的话,面试官一般都会问还没有其他办法,这时候你肯定要说怎么没有,所以我们做一道题不能仅仅限于做出了,要从多方面下手,使得复杂度越小越好。
所以我们要仔细审题,我们看到题目中有这样一句描述**矩阵中的元素无论是按行还是按列,都以非递增顺序排列**,这句话信息量很大,你品,你仔细品。
首先我们可以理解到的是:一个 m * n 的矩阵 grid,grid[i][j]<0的话,i那一行第j个到数组最后一个都是小于0,第i行开始,j到后面的列都是小于0
我们举个例子
```
[
[4, 3, -1, -1],
[3, 2, -1, -1],
[1, 1, -1, -2],
[-1, -1, -2, -3]
]
```
可以看到第一行第三列的值小于0,那么第一行及后面几行的第三列和后面的列的值都小于0。
所以我们可以进行倒序遍历,找到负数的左边界,也就是左边第一个为负数的值。
i为行遍历的指针,j为列遍历指针,count为负数的个数,len1为**当前行**的个数,len2为**当前列**的个数
```
初始值
let count = 0;
let len1 = grid.length
let len2 = grid[0].length
let i = 0;
let j = len2 - 1;
```
然后我们倒序遍历列,行还是正序遍历,以上面的例子来说,我们找到的第一个负数是grid[0][2],然后我们能确定的负数就有如下,所以我们count就可以加上(len1 - i -1) * (len2 - j )
```
[
[ -1, -1],
[ -1, -1],
[ -1, -2],
[ -2, -3]
]
```
然后我们遍历的矩阵就变成如下,然后重复上面操作。
```
[
[3, 2],
[1, 1],
[-1, -1]
]
```
所以我们每次遍历后要更新len1和len2,具体看代码和动画。
## 动画理解
<video id="video" controls="" preload="none" >
<source id="mp4" src="../Animation/1351.mp4" type="video/mp4">
</video>
## 参考代码
```JavaScript
/**
* @param {number[][]} arr
* @return {number}
*/
var countNegatives = function(arr) {
if (arr.length <= 0 ) {return 0}
let count = 0;
let len1 = arr.length;
let len2 = arr[0].length;
let i = 0;
let j = len2 - 1;
while(i < len1) {
while(j >= 0) {
if (arr[i][j] < 0) {
if (j==0){
count += (len2 * (len1 - i))
len2 = 0
break
}
j--
}else {
if (len2 == j + 1) {
break
}
count += ((len2 - j - 1) * (len1 - i))
len2 = j + 1
break
}
}
i++
j= len2 - 1
}
return count
};
```
## 复杂度分析
时间复杂度: O(mn)。 因为如果矩阵中所有的数都为正数,那么要遍历整个矩阵,所以时间复杂度是O(mn)。
空间复杂度:O(1)。
![](../../Pictures/qrcode.jpg)
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment