mirror of
https://github.com/Estom/notes.git
synced 2026-04-24 02:21:45 +08:00
位运算
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
& | 按位与 | 只要有0,返回0
|
||||
\| | 按位或| 只要有1,返回1
|
||||
^ | 按位异或| 相同返回0。不同返回1
|
||||
\~ | 按位取反| 全部反转
|
||||
\~ | 按位取反| 全部反转。不重复的数字
|
||||
\>\> | 右移|
|
||||
<< | 左移|
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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=j−1 ;
|
||||
若 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;
|
||||
}
|
||||
```
|
||||
@@ -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 求余,结果则为只出现一次的数字
|
||||
|
||||

|
||||
|
||||
### 策略选择
|
||||
|
||||
* 算法思想:变治法
|
||||
|
||||
### 算法设计
|
||||
|
||||
* 使用 与运算 ,可获取二进制数字 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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
BIN
算法/C类:问题类型算法/image/2021-03-26-22-07-44.png
Normal file
BIN
算法/C类:问题类型算法/image/2021-03-26-22-07-44.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
Reference in New Issue
Block a user