位运算

This commit is contained in:
estomm
2021-03-27 11:30:07 +08:00
parent 8cbe651ad0
commit cf638659dd
5 changed files with 212 additions and 2 deletions

View File

@@ -9,7 +9,7 @@
& | 按位与 | 只要有0返回0
\| | 按位或| 只要有1返回1
^ | 按位异或| 相同返回0。不同返回1
\~ | 按位取反| 全部反转
\~ | 按位取反| 全部反转。不重复的数字
\>\> | 右移|
<< | 左移|

View File

@@ -15,4 +15,54 @@
* 请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
* [链接](https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof/)
## 4 二叉搜索树的第k大节点
* 给定一棵二叉搜索树请找出其中第k大的节点。
* 示例 1:
```
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
  2
输出: 4
示例 2:
```
* [链接](https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof)
## 5 二叉树的深度
* 输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
* 例如:
```
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
```
* [链接](https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof)
## 6 平衡二叉树
* 输入一棵二叉树的根节点判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1那么它就是一棵平衡二叉树。
 
* 示例 1:
```
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
```
* [链接](https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof)

View File

@@ -96,4 +96,50 @@ public:
return node1;
}
};
```
## 3 和为s的两个数字
### 问题描述
* 输入一个递增排序的数组和一个数字s在数组中查找两个数使得它们的和正好是s。如果有多对数字的和等于s则输出任意一对即可。
* 示例 1
```
输入nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]
```
### 问题分析
### 策略选择
* 数据结构:线型数组
* 算法思想:双指针搜搜
### 算法设计
始化: 双指针 ii , jj 分别指向数组 numsnums 的左右两端 (俗称对撞双指针)。
循环搜索: 当双指针相遇时跳出;
计算和 s = nums[i] + nums[j]s=nums[i]+nums[j]
若 s > targets>target ,则指针 jj 向左移动,即执行 j = j - 1j=j1
若 s < targets<target ,则指针 ii 向右移动,即执行 i = i + 1i=i+1
若 s = targets=target ,立即返回数组 [nums[i], nums[j]][nums[i],nums[j]]
返回空数组,代表无和为 targettarget 的数字组合。
### 算法分析
* 时间复杂度 O(N) N为数组 nums 的长度;双指针共同线性遍历整个数组。
* 空间复杂度 O(1) 变量 i, j 使用常数大小的额外空间。
### 算法实现
```C++
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> vec;
int i=0,j=nums.size()-1;
while(nums[i]+nums[j]!=target){
if(nums[i]+nums[j]>target)j--;
if(nums[i]+nums[j]<target)i++;
}
vec.push_back(nums[i]);
vec.push_back(nums[j]);
return vec;
}
```

View File

@@ -157,4 +157,118 @@ public:
return x;
}
};
```
```
## 3 数组中数字出现的次数I
### 问题描述
* 一个整型数组 nums 里除两个数字之外其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n)空间复杂度是O(1)。
* 示例 1
```
输入nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
```
### 问题分析
* 问题类别:重复查找问题
### 策略选择
* 数据结构:线性数据结构
* 算法思想:位运算
### 算法设计
* 如果除了一个数字以外,其他数字都出现了两次,那么如何找到出现一次的数字?
* 答案很简单:全员进行异或操作即可。考虑异或操作的性质:对于两个操作数的每一位,相同结果为 00不同结果为 11。那么在计算过程中成对出现的数字的所有位会两两抵消为 00最终得到的结果就是那个出现了一次的数字。
* 如果有两位一样
* 先对所有数字进行一次异或,得到两个出现一次的数字的异或值。
* 在异或结果中找到任意为 1的位.
* 根据这一位对所有的数字进行分组。
* 在每个组内进行异或操作,得到两个数字。
### 算法分析
* 时间复杂度O(n),我们只需要遍历数组两次
* 空间复杂度O(1),只需要常数的空间存放若干变量。
### 算法实现
```
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int ret = 0;
for (int n : nums)
ret ^= n;
int div = 1;
while ((div & ret) == 0)
div <<= 1;
//可以优化while循环
//div = n & ((~n)-1)//lowbit()运算保留最后一位1
int a = 0, b = 0;
for (int n : nums)
if (div & n)
a ^= n;
else
b ^= n;
return vector<int>{a, b};
}
};
```
## 4 数组中数字出现的次数II
### 问题描述
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
* 示例 1
```
输入nums = [3,4,3,3]
输出4
```
### 问题分析
* 问题分类:查找重复
* 问题抽象:如下图所示,考虑数字的二进制形式,对于出现三次的数字,各 二进制位 出现的次数都是 33 的倍数。因此,统计所有数字的各二进制位中 11 的出现次数,并对 33 求余,结果则为只出现一次的数字
![](image/2021-03-26-22-07-44.png)
### 策略选择
* 算法思想:变治法
### 算法设计
* 使用 与运算 ,可获取二进制数字 num 的最右一位$n_1$ $n_1 = num \& 1$
* 配合 无符号右移操作 ,可获取 num 所有位的$n_1$ $num = num >> 1$
* 建立一个长度为 32 的数组 countscounts ,通过以上方法可记录所有数字的各二进制位的 11 的出现次数。
* 将 countscounts 各元素对 33 求余,则结果为 “只出现一次的数字” 的各二进制位。
### 算法分析
* 时间复杂度 O(N)
* 空间复杂度 O(1)
### 算法实现
```java
class Solution {
public int singleNumber(int[] nums) {
int[] counts = new int[32];
for(int num : nums) {
for(int j = 0; j < 32; j++) {
counts[j] += num & 1;
num >>>= 1;
}
}
int res = 0, m = 3;
for(int i = 0; i < 32; i++) {
res <<= 1;
res |= counts[31 - i] % m;
}
return res;
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB