mirror of
https://github.com/krahets/hello-algo.git
synced 2025-07-18 02:50:19 +08:00
build
This commit is contained in:
@ -35,7 +35,7 @@ We can imagine the computer storage system as a pyramid structure shown in the F
|
||||
|
||||
<p align="center"> Figure 4-9 Computer storage system </p>
|
||||
|
||||
!!! note
|
||||
!!! tip
|
||||
|
||||
The storage hierarchy of computers reflects a delicate balance between speed, capacity, and cost. In fact, this kind of trade-off is common in all industrial fields, requiring us to find the best balance between different advantages and limitations.
|
||||
|
||||
|
@ -671,7 +671,7 @@ Since $T(n)$ is a linear function, its growth trend is linear, and therefore, it
|
||||
|
||||
In essence, time complexity analysis is about finding the asymptotic upper bound of the "number of operations $T(n)$". It has a precise mathematical definition.
|
||||
|
||||
!!! abstract "Asymptotic Upper Bound"
|
||||
!!! note "Asymptotic Upper Bound"
|
||||
|
||||
If there exist positive real numbers $c$ and $n_0$ such that for all $n > n_0$, $T(n) \leq c \cdot f(n)$, then $f(n)$ is considered an asymptotic upper bound of $T(n)$, denoted as $T(n) = O(f(n))$.
|
||||
|
||||
|
@ -4,7 +4,7 @@ comments: true
|
||||
|
||||
# 3.3 Number encoding *
|
||||
|
||||
!!! note
|
||||
!!! tip
|
||||
|
||||
In this book, chapters marked with an asterisk '*' are optional readings. If you are short on time or find them challenging, you may skip these initially and return to them after completing the essential chapters.
|
||||
|
||||
|
@ -34,7 +34,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
# 顶点遍历序列
|
||||
res = []
|
||||
# 哈希表,用于记录已被访问过的顶点
|
||||
# 哈希集合,用于记录已被访问过的顶点
|
||||
visited = set[Vertex]([start_vet])
|
||||
# 队列用于实现 BFS
|
||||
que = deque[Vertex]([start_vet])
|
||||
@ -60,7 +60,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
vector<Vertex *> graphBFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 顶点遍历序列
|
||||
vector<Vertex *> res;
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
unordered_set<Vertex *> visited = {startVet};
|
||||
// 队列用于实现 BFS
|
||||
queue<Vertex *> que;
|
||||
@ -91,7 +91,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
List<Vertex> graphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
List<Vertex> res = new ArrayList<>();
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
Set<Vertex> visited = new HashSet<>();
|
||||
visited.add(startVet);
|
||||
// 队列用于实现 BFS
|
||||
@ -122,7 +122,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
List<Vertex> GraphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
List<Vertex> res = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
HashSet<Vertex> visited = [startVet];
|
||||
// 队列用于实现 BFS
|
||||
Queue<Vertex> que = new();
|
||||
@ -153,7 +153,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
func graphBFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 顶点遍历序列
|
||||
res := make([]Vertex, 0)
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
visited := make(map[Vertex]struct{})
|
||||
visited[startVet] = struct{}{}
|
||||
// 队列用于实现 BFS, 使用切片模拟队列
|
||||
@ -189,7 +189,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
func graphBFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] {
|
||||
// 顶点遍历序列
|
||||
var res: [Vertex] = []
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
var visited: Set<Vertex> = [startVet]
|
||||
// 队列用于实现 BFS
|
||||
var que: [Vertex] = [startVet]
|
||||
@ -219,7 +219,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
function graphBFS(graph, startVet) {
|
||||
// 顶点遍历序列
|
||||
const res = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
const visited = new Set();
|
||||
visited.add(startVet);
|
||||
// 队列用于实现 BFS
|
||||
@ -250,7 +250,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
function graphBFS(graph: GraphAdjList, startVet: Vertex): Vertex[] {
|
||||
// 顶点遍历序列
|
||||
const res: Vertex[] = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
const visited: Set<Vertex> = new Set();
|
||||
visited.add(startVet);
|
||||
// 队列用于实现 BFS
|
||||
@ -281,7 +281,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
// 顶点遍历序列
|
||||
List<Vertex> res = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
Set<Vertex> visited = {};
|
||||
visited.add(startVet);
|
||||
// 队列用于实现 BFS
|
||||
@ -313,7 +313,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// 顶点遍历序列
|
||||
let mut res = vec![];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
let mut visited = HashSet::new();
|
||||
visited.insert(start_vet);
|
||||
// 队列用于实现 BFS
|
||||
@ -421,7 +421,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
fun graphBFS(graph: GraphAdjList, startVet: Vertex): MutableList<Vertex?> {
|
||||
// 顶点遍历序列
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
val visited = HashSet<Vertex>()
|
||||
visited.add(startVet)
|
||||
// 队列用于实现 BFS
|
||||
@ -452,7 +452,7 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
|
||||
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
# 顶点遍历序列
|
||||
res = []
|
||||
# 哈希表,用于记录已被访问过的顶点
|
||||
# 哈希集合,用于记录已被访问过的顶点
|
||||
visited = Set.new([start_vet])
|
||||
# 队列用于实现 BFS
|
||||
que = [start_vet]
|
||||
@ -561,7 +561,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
# 顶点遍历序列
|
||||
res = []
|
||||
# 哈希表,用于记录已被访问过的顶点
|
||||
# 哈希集合,用于记录已被访问过的顶点
|
||||
visited = set[Vertex]()
|
||||
dfs(graph, visited, res, start_vet)
|
||||
return res
|
||||
@ -588,7 +588,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
vector<Vertex *> graphDFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 顶点遍历序列
|
||||
vector<Vertex *> res;
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
unordered_set<Vertex *> visited;
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@ -616,7 +616,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
List<Vertex> res = new ArrayList<>();
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
Set<Vertex> visited = new HashSet<>();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@ -645,7 +645,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
List<Vertex> GraphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
List<Vertex> res = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
HashSet<Vertex> visited = [];
|
||||
DFS(graph, visited, res, startVet);
|
||||
return res;
|
||||
@ -675,7 +675,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
func graphDFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 顶点遍历序列
|
||||
res := make([]Vertex, 0)
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
visited := make(map[Vertex]struct{})
|
||||
dfs(g, visited, &res, startVet)
|
||||
// 返回顶点遍历序列
|
||||
@ -705,7 +705,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
func graphDFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] {
|
||||
// 顶点遍历序列
|
||||
var res: [Vertex] = []
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
var visited: Set<Vertex> = []
|
||||
dfs(graph: graph, visited: &visited, res: &res, vet: startVet)
|
||||
return res
|
||||
@ -735,7 +735,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
function graphDFS(graph, startVet) {
|
||||
// 顶点遍历序列
|
||||
const res = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
const visited = new Set();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@ -769,7 +769,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
function graphDFS(graph: GraphAdjList, startVet: Vertex): Vertex[] {
|
||||
// 顶点遍历序列
|
||||
const res: Vertex[] = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
const visited: Set<Vertex> = new Set();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@ -802,7 +802,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
List<Vertex> res = [];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
Set<Vertex> visited = {};
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@ -833,7 +833,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// 顶点遍历序列
|
||||
let mut res = vec![];
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
let mut visited = HashSet::new();
|
||||
dfs(&graph, &mut visited, &mut res, start_vet);
|
||||
|
||||
@ -904,7 +904,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
fun graphDFS(graph: GraphAdjList, startVet: Vertex?): MutableList<Vertex?> {
|
||||
// 顶点遍历序列
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
// 哈希集合,用于记录已被访问过的顶点
|
||||
val visited = HashSet<Vertex?>()
|
||||
dfs(graph, visited, res, startVet)
|
||||
return res
|
||||
@ -931,7 +931,7 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
|
||||
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
# 顶点遍历序列
|
||||
res = []
|
||||
# 哈希表,用于记录已被访问过的顶点
|
||||
# 哈希集合,用于记录已被访问过的顶点
|
||||
visited = Set.new
|
||||
dfs(graph, visited, res, start_vet)
|
||||
res
|
||||
|
@ -675,11 +675,20 @@ We can encapsulate the index mapping formula into functions for convenient later
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="my_heap.rb"
|
||||
[class]{MaxHeap}-[func]{left}
|
||||
### 获取左子节点的索引 ###
|
||||
def left(i)
|
||||
2 * i + 1
|
||||
end
|
||||
|
||||
[class]{MaxHeap}-[func]{right}
|
||||
### 获取右子节点的索引 ###
|
||||
def right(i)
|
||||
2 * i + 2
|
||||
end
|
||||
|
||||
[class]{MaxHeap}-[func]{parent}
|
||||
### 获取父节点的索引 ###
|
||||
def parent(i)
|
||||
(i - 1) / 2 # 向下整除
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -816,7 +825,10 @@ The top element of the heap is the root node of the binary tree, which is also t
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="my_heap.rb"
|
||||
[class]{MaxHeap}-[func]{peek}
|
||||
### 访问堆顶元素 ###
|
||||
def peek
|
||||
@max_heap[0]
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -1210,9 +1222,27 @@ Given a total of $n$ nodes, the height of the tree is $O(\log n)$. Hence, the lo
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="my_heap.rb"
|
||||
[class]{MaxHeap}-[func]{push}
|
||||
### 元素入堆 ###
|
||||
def push(val)
|
||||
# 添加节点
|
||||
@max_heap << val
|
||||
# 从底至顶堆化
|
||||
sift_up(size - 1)
|
||||
end
|
||||
|
||||
[class]{MaxHeap}-[func]{sift_up}
|
||||
### 从节点 i 开始,从底至顶堆化 ###
|
||||
def sift_up(i)
|
||||
loop do
|
||||
# 获取节点 i 的父节点
|
||||
p = parent(i)
|
||||
# 当“越过根节点”或“节点无须修复”时,结束堆化
|
||||
break if p < 0 || @max_heap[i] <= @max_heap[p]
|
||||
# 交换两节点
|
||||
swap(i, p)
|
||||
# 循环向上堆化
|
||||
i = p
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -1648,7 +1678,7 @@ Similar to the element insertion operation, the time complexity of the top eleme
|
||||
// 交换根节点与最右叶节点(交换首元素与尾元素)
|
||||
self.swap(0, self.size() - 1);
|
||||
// 删除节点
|
||||
let val = self.max_heap.remove(self.size() - 1);
|
||||
let val = self.max_heap.pop().unwrap();
|
||||
// 从顶至底堆化
|
||||
self.sift_down(0);
|
||||
// 返回堆顶元素
|
||||
@ -1766,9 +1796,37 @@ Similar to the element insertion operation, the time complexity of the top eleme
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="my_heap.rb"
|
||||
[class]{MaxHeap}-[func]{pop}
|
||||
### 元素出堆 ###
|
||||
def pop
|
||||
# 判空处理
|
||||
raise IndexError, "堆为空" if is_empty?
|
||||
# 交换根节点与最右叶节点(交换首元素与尾元素)
|
||||
swap(0, size - 1)
|
||||
# 删除节点
|
||||
val = @max_heap.pop
|
||||
# 从顶至底堆化
|
||||
sift_down(0)
|
||||
# 返回堆顶元素
|
||||
val
|
||||
end
|
||||
|
||||
[class]{MaxHeap}-[func]{sift_down}
|
||||
### 从节点 i 开始,从顶至底堆化 ###
|
||||
def sift_down(i)
|
||||
loop do
|
||||
# 判断节点 i, l, r 中值最大的节点,记为 ma
|
||||
l, r, ma = left(i), right(i), i
|
||||
ma = l if l < size && @max_heap[l] > @max_heap[ma]
|
||||
ma = r if r < size && @max_heap[r] > @max_heap[ma]
|
||||
|
||||
# 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出
|
||||
break if ma == i
|
||||
|
||||
# 交换两节点
|
||||
swap(i, ma)
|
||||
# 循环向下堆化
|
||||
i = ma
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -437,7 +437,28 @@ Example code is as follows:
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="top_k.rb"
|
||||
[class]{}-[func]{top_k_heap}
|
||||
### 基于堆查找数组中最大的 k 个元素 ###
|
||||
def top_k_heap(nums, k)
|
||||
# 初始化小顶堆
|
||||
# 请注意:我们将堆中所有元素取反,从而用大顶堆来模拟小顶堆
|
||||
max_heap = MaxHeap.new([])
|
||||
|
||||
# 将数组的前 k 个元素入堆
|
||||
for i in 0...k
|
||||
push_min_heap(max_heap, nums[i])
|
||||
end
|
||||
|
||||
# 从第 k+1 个元素开始,保持堆的长度为 k
|
||||
for i in k...nums.length
|
||||
# 若当前元素大于堆顶元素,则将堆顶元素出堆、当前元素入堆
|
||||
if nums[i] > peek_min_heap(max_heap)
|
||||
pop_min_heap(max_heap)
|
||||
push_min_heap(max_heap, nums[i])
|
||||
end
|
||||
end
|
||||
|
||||
get_min_heap(max_heap)
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -670,7 +670,7 @@ The "balance factor" of a node is defined as the height of the node's left subtr
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
!!! tip
|
||||
|
||||
Let the balance factor be $f$, then the balance factor of any node in an AVL tree satisfies $-1 \le f \le 1$.
|
||||
|
||||
|
@ -617,7 +617,7 @@ Similar to a linked list, inserting and removing nodes in a binary tree can be a
|
||||
|
||||
https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%8F%89%E6%A0%91%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BA%8C%E5%8F%89%E6%A0%91%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E8%8A%82%E7%82%B9%0A%20%20%20%20n1%20%3D%20TreeNode%28val%3D1%29%0A%20%20%20%20n2%20%3D%20TreeNode%28val%3D2%29%0A%20%20%20%20n3%20%3D%20TreeNode%28val%3D3%29%0A%20%20%20%20n4%20%3D%20TreeNode%28val%3D4%29%0A%20%20%20%20n5%20%3D%20TreeNode%28val%3D5%29%0A%20%20%20%20%23%20%E6%9E%84%E5%BB%BA%E8%8A%82%E7%82%B9%E4%B9%8B%E9%97%B4%E7%9A%84%E5%BC%95%E7%94%A8%EF%BC%88%E6%8C%87%E9%92%88%EF%BC%89%0A%20%20%20%20n1.left%20%3D%20n2%0A%20%20%20%20n1.right%20%3D%20n3%0A%20%20%20%20n2.left%20%3D%20n4%0A%20%20%20%20n2.right%20%3D%20n5%0A%0A%20%20%20%20%23%20%E6%8F%92%E5%85%A5%E4%B8%8E%E5%88%A0%E9%99%A4%E8%8A%82%E7%82%B9%0A%20%20%20%20p%20%3D%20TreeNode%280%29%0A%20%20%20%20%23%20%E5%9C%A8%20n1%20-%3E%20n2%20%E4%B8%AD%E9%97%B4%E6%8F%92%E5%85%A5%E8%8A%82%E7%82%B9%20P%0A%20%20%20%20n1.left%20%3D%20p%0A%20%20%20%20p.left%20%3D%20n2%0A%20%20%20%20%23%20%E5%88%A0%E9%99%A4%E8%8A%82%E7%82%B9%20P%0A%20%20%20%20n1.left%20%3D%20n2&cumulative=false&curInstr=37&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false
|
||||
|
||||
!!! note
|
||||
!!! tip
|
||||
|
||||
It's important to note that inserting nodes may change the original logical structure of the binary tree, while removing nodes usually means removing the node and all its subtrees. Therefore, in a binary tree, insertion and removal are usually performed through a set of operations to achieve meaningful actions.
|
||||
|
||||
|
Reference in New Issue
Block a user