|
44 | 44 | * [BST](#bst)
|
45 | 45 | * [Trie](#trie)
|
46 | 46 | * [图](#图)
|
| 47 | + * [拓扑排序](#拓扑排序) |
| 48 | + * [并查集](#并查集) |
47 | 49 | * [位运算](#位运算)
|
48 | 50 | * [参考资料](#参考资料)
|
49 | 51 | <!-- GFM-TOC -->
|
@@ -3447,14 +3449,14 @@ public int majorityElement(int[] nums) {
|
3447 | 3449 | }
|
3448 | 3450 | ```
|
3449 | 3451 |
|
3450 |
| -可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(N)。可以这么理解该算法:使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不相等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0 ,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。 |
| 3452 | +可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(N)。可以这么理解该算法:使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不相等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2,因为如果多于 i / 2 的话 cnt 就一定不会为 0。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。 |
3451 | 3453 |
|
3452 | 3454 | ```java
|
3453 | 3455 | public int majorityElement(int[] nums) {
|
3454 |
| - int cnt = 1, majority = nums[0]; |
3455 |
| - for (int i = 1; i < nums.length; i++) { |
3456 |
| - majority = (cnt == 0) ? nums[i] : majority; |
3457 |
| - cnt = (majority == nums[i]) ? cnt + 1 : cnt - 1; |
| 3456 | + int cnt = 0, majority = nums[0]; |
| 3457 | + for (int num : nums) { |
| 3458 | + majority = (cnt == 0) ? num : majority; |
| 3459 | + cnt = (majority == num) ? cnt + 1 : cnt - 1; |
3458 | 3460 | }
|
3459 | 3461 | return majority;
|
3460 | 3462 | }
|
@@ -5912,6 +5914,122 @@ class MapSum {
|
5912 | 5914 |
|
5913 | 5915 | ## 图
|
5914 | 5916 |
|
| 5917 | +### 拓扑排序 |
| 5918 | + |
| 5919 | +常用于在具有先序关系的任务规划中。 |
| 5920 | + |
| 5921 | +**课程安排的合法性** |
| 5922 | + |
| 5923 | +[Leetcode : 207. Course Schedule (Medium)](https://leetcode.com/problems/course-schedule/description/) |
| 5924 | + |
| 5925 | +```html |
| 5926 | +2, [[1,0]] |
| 5927 | +return true |
| 5928 | +``` |
| 5929 | + |
| 5930 | +```html |
| 5931 | +2, [[1,0],[0,1]] |
| 5932 | +return false |
| 5933 | +``` |
| 5934 | + |
| 5935 | +题目描述:一个课程可能会先修课程,判断给定的先修课程规定是否合法。 |
| 5936 | + |
| 5937 | +本题不需要使用拓扑排序,只需要检测有向图是否存在环即可。 |
| 5938 | + |
| 5939 | +```java |
| 5940 | +public boolean canFinish(int numCourses, int[][] prerequisites) { |
| 5941 | + List<Integer>[] graphic = new List[numCourses]; |
| 5942 | + for (int i = 0; i < numCourses; i++) |
| 5943 | + graphic[i] = new ArrayList<>(); |
| 5944 | + for (int[] pre : prerequisites) |
| 5945 | + graphic[pre[0]].add(pre[1]); |
| 5946 | + |
| 5947 | + boolean[] globalMarked = new boolean[numCourses]; |
| 5948 | + boolean[] localMarked = new boolean[numCourses]; |
| 5949 | + for (int i = 0; i < numCourses; i++) |
| 5950 | + if (!dfs(globalMarked, localMarked, graphic, i)) |
| 5951 | + return false; |
| 5952 | + |
| 5953 | + return true; |
| 5954 | +} |
| 5955 | + |
| 5956 | +private boolean dfs(boolean[] globalMarked, boolean[] localMarked, List<Integer>[] graphic, int curNode) { |
| 5957 | + if (localMarked[curNode]) |
| 5958 | + return false; |
| 5959 | + if (globalMarked[curNode]) |
| 5960 | + return true; |
| 5961 | + |
| 5962 | + globalMarked[curNode] = true; |
| 5963 | + localMarked[curNode] = true; |
| 5964 | + |
| 5965 | + for (int nextNode : graphic[curNode]) |
| 5966 | + if (!dfs(globalMarked, localMarked, graphic, nextNode)) |
| 5967 | + return false; |
| 5968 | + |
| 5969 | + localMarked[curNode] = false; |
| 5970 | + |
| 5971 | + return true; |
| 5972 | +} |
| 5973 | +``` |
| 5974 | + |
| 5975 | +**课程安排的顺序** |
| 5976 | + |
| 5977 | +[Leetcode : 210. Course Schedule II (Medium)](https://leetcode.com/problems/course-schedule-ii/description/) |
| 5978 | + |
| 5979 | +```html |
| 5980 | +4, [[1,0],[2,0],[3,1],[3,2]] |
| 5981 | +There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3]. |
| 5982 | +``` |
| 5983 | + |
| 5984 | +使用 DFS 来实现拓扑排序,使用一个栈存储后序遍历结果,这个栈元素的逆序结果就是拓扑排序结果。 |
| 5985 | + |
| 5986 | +证明:对于任何先序关系:v->w,后序遍历结果可以保证 w 先进入栈中,因此栈的逆序结果中 v 会在 w 之前。 |
| 5987 | + |
| 5988 | +```java |
| 5989 | +public int[] findOrder(int numCourses, int[][] prerequisites) { |
| 5990 | + List<Integer>[] graphic = new List[numCourses]; |
| 5991 | + for (int i = 0; i < numCourses; i++) |
| 5992 | + graphic[i] = new ArrayList<>(); |
| 5993 | + for (int[] pre : prerequisites) |
| 5994 | + graphic[pre[0]].add(pre[1]); |
| 5995 | + |
| 5996 | + Stack<Integer> topologyOrder = new Stack<>(); |
| 5997 | + boolean[] globalMarked = new boolean[numCourses]; |
| 5998 | + boolean[] localMarked = new boolean[numCourses]; |
| 5999 | + for (int i = 0; i < numCourses; i++) |
| 6000 | + if (!dfs(globalMarked, localMarked, graphic, i, topologyOrder)) |
| 6001 | + return new int[0]; |
| 6002 | + |
| 6003 | + int[] ret = new int[numCourses]; |
| 6004 | + for (int i = numCourses - 1; i >= 0; i--) |
| 6005 | + ret[i] = topologyOrder.pop(); |
| 6006 | + return ret; |
| 6007 | +} |
| 6008 | + |
| 6009 | +private boolean dfs(boolean[] globalMarked, boolean[] localMarked, List<Integer>[] graphic, int curNode, Stack<Integer> topologyOrder) { |
| 6010 | + if (localMarked[curNode]) |
| 6011 | + return false; |
| 6012 | + if (globalMarked[curNode]) |
| 6013 | + return true; |
| 6014 | + |
| 6015 | + globalMarked[curNode] = true; |
| 6016 | + localMarked[curNode] = true; |
| 6017 | + |
| 6018 | + for (int nextNode : graphic[curNode]) |
| 6019 | + if (!dfs(globalMarked, localMarked, graphic, nextNode, topologyOrder)) |
| 6020 | + return false; |
| 6021 | + |
| 6022 | + localMarked[curNode] = false; |
| 6023 | + topologyOrder.push(curNode); |
| 6024 | + |
| 6025 | + return true; |
| 6026 | +} |
| 6027 | +``` |
| 6028 | + |
| 6029 | +### 并查集 |
| 6030 | + |
| 6031 | +并查集可以动态地连通两个点,并且可以非常快速地判断两个点是否连通。 |
| 6032 | + |
5915 | 6033 | **冗余连接**
|
5916 | 6034 |
|
5917 | 6035 | [Leetcode : 684. Redundant Connection (Medium)](https://leetcode.com/problems/redundant-connection/description/)
|
|
0 commit comments