diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index 59c369db..68bd61b3 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -596,7 +596,7 @@ Output: "apple" ``` -题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。 +题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回按字典序排序的最大字符串。 ```java public String findLongestWord(String s, List d) { @@ -632,7 +632,7 @@ public String findLongestWord(String s, List d) { [Leetocde : 215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/) -**排序** :时间复杂度 O(nlgn),空间复杂度 O(1) 解法 +**排序** :时间复杂度 O(nlgn),空间复杂度 O(1) ```java public int findKthLargest(int[] nums, int k) { @@ -706,7 +706,7 @@ public int findKthLargest(int[] nums, int k) { ### 桶排序 -**找出出现频率最多的 k 个数** +**出现频率最多的 k 个数** [Leetcode : 347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/) @@ -714,6 +714,8 @@ public int findKthLargest(int[] nums, int k) { Given [1,1,1,2,2,3] and k = 2, return [1,2]. ``` +设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率,即第 i 个桶中存储的数出现的频率为 i。把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。 + ```java public List topKFrequent(int[] nums, int k) { List ret = new ArrayList<>(); @@ -747,28 +749,42 @@ public List topKFrequent(int[] nums, int k) {

-广度优先搜索的搜索过程有点像一层一层地进行遍历:从节点 0 出发,遍历到 6、2、1 和 5 这四个新节点。 +广度优先搜索的搜索过程有点像一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个长度。需要注意的是,遍历过的节点不能再次被遍历。 -继续从 6 开始遍历,得到节点 4 ;从 2 开始遍历,没有下一个节点;从 1 开始遍历,没有下一个节点;从 5 开始遍历,得到 3 和 4 节点。这一轮总共得到两个新节点:4 和 3 。 +第一层: -反复从新节点出发进行上述的遍历操作。 +- 0 -> {6,2,1,5}; -可以看到,每一轮遍历的节点都与根节点路径长度相同。设 di 表示第 i 个节点与根节点的路径长度,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di<=dj。利用这个结论,可以求解最短路径 **最优解** 问题:第一次遍历到目的节点,其所经过的路径为最短路径,如果继续遍历,之后再遍历到目的节点,所经过的路径就不是最短路径。 +第二层: + +- 6 -> {4} +- 2 -> {} +- 1 -> {} +- 5 -> {4,3} + +第三层: + +- 4 -> {} +- 3 -> {} + +可以看到,每一轮遍历的节点都与根节点路径长度相同。设 di 表示第 i 个节点与根节点的路径长度,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di<=dj。利用这个结论,可以求解最短路径等 **最优解** 问题:第一次遍历到目的节点,其所经过的路径为最短路径,如果继续遍历,之后再遍历到目的节点,所经过的路径就不是最短路径。 在程序实现 BFS 时需要考虑以下问题: -- 队列:用来存储每一轮遍历的节点 -- 标记:对于遍历过得节点,应该将它标记,防止重复遍历; +- 队列:用来存储每一轮遍历的节点; +- 标记:对于遍历过的节点,应该将它标记,防止重复遍历。 **计算在网格中从原点到特定点的最短路径长度** ```html [[1,1,0,1], -[1,0,1,0], -[1,1,1,1], -[1,0,1,1]] + [1,0,1,0], + [1,1,1,1], + [1,0,1,1]] ``` +1 表示可以经过某个位置。 + ```java public int minPathLength(int[][] grids, int tr, int tc) { int[][] next = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; @@ -803,14 +819,14 @@ private class Position {

-广度优先搜索一层一层遍历,每一层遍历到的所有新节点,要用队列先存储起来以备下一层遍历的时候再遍历;而深度优先搜索在遍历到一个新节点时立马对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4;如此反复以这种方式遍历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2,然后继续以上步骤。 +广度优先搜索一层一层遍历,每一层得到到的所有新节点,要用队列先存储起来以备下一层遍历的时候再遍历;而深度优先搜索在得到到一个新节点时立马对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4;如此反复以这种方式遍历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2,然后继续以上步骤。 从一个节点出发,使用 DFS 对一个图进行遍历时,能够遍历到的节点都是从初始节点可达的,DFS 常用来求解这种 **可达性** 问题。 在程序实现 DFS 时需要考虑以下问题: -- 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。也可以使用递归栈。 -- 标记:和 BFS 一样同样需要对已经遍历过得节点进行标记。 +- 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。可以使用递归栈。 +- 标记:和 BFS 一样同样需要对已经遍历过的节点进行标记。 **查找最大的连通面积** @@ -818,13 +834,13 @@ private class Position { ```html [[0,0,1,0,0,0,0,1,0,0,0,0,0], -[0,0,0,0,0,0,0,1,1,1,0,0,0], -[0,1,1,0,1,0,0,0,0,0,0,0,0], -[0,1,0,0,1,1,0,0,1,0,1,0,0], -[0,1,0,0,1,1,0,0,1,1,1,0,0], -[0,0,0,0,0,0,0,0,0,0,1,0,0], -[0,0,0,0,0,0,0,1,1,1,0,0,0], -[0,0,0,0,0,0,0,1,1,0,0,0,0]] + [0,0,0,0,0,0,0,1,1,1,0,0,0], + [0,1,1,0,1,0,0,0,0,0,0,0,0], + [0,1,0,0,1,1,0,0,1,0,1,0,0], + [0,1,0,0,1,1,0,0,1,1,1,0,0], + [0,0,0,0,0,0,0,0,0,0,1,0,0], + [0,0,0,0,0,0,0,1,1,1,0,0,0], + [0,0,0,0,0,0,0,1,1,0,0,0,0]] ``` ```java diff --git a/notes/分布式问题分析.md b/notes/分布式问题分析.md index cb029c03..5862ca48 100644 --- a/notes/分布式问题分析.md +++ b/notes/分布式问题分析.md @@ -194,7 +194,7 @@ EXPIRE 可以为一个键值对设置一个过期时间,从而避免了死锁 **(二)RedLock 算法** -ReadLock 算法使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时还可用。 +RedLock 算法使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时还可用。 1. 尝试从 N 个相互独立 Redis 实例获取锁,如果一个实例不可用,应该尽快尝试下一个。 2. 计算获取锁消耗的时间,只有当这个时间小于锁的过期时间,并且从大多数(N/2+1)实例上获取了锁,那么就认为锁获取成功了。