Copyright © 直通硅谷
http://www.zhitongguigu.com/
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Disjoint-set Structure (Union-find Structure)
a data structure that keeps track of a set of elements partitioned into a number of disjoint (nonoverlapping) subsets.
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to find the number of connected components in an undirected graph.
Example 1:
0 3
| |
1 --- 2 4
Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], return 2.
Example 2:
0 4
| |
1 --- 2 --- 3
Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [3, 4]], return 1.
Note:
You can assume that no duplicate edges will appear in edges.
Since all edges are undirected, [0, 1] is the same as [1, 0]
and thus will not appear together in edges.
public int countComponents(int n, int[][] edges) {
// Code here
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
int[] parent;
public int countComponents(int n, int[][] edges) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
for (int i = 0; i < edges.length; i++) {
union(edges[i][0], edges[i][1]);
}
Set<Integer> hs = new HashSet<>();
for (int i = 0; i < n; i++) {
hs.add(find(parent[i]));
}
return hs.size();
}
private void union(int node1, int node2) {
parent[find(node1)] = find(node2);
}
private int find(int node) {
if (parent[node] == node) {
return node;
}
return find(parent[node]);
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
int[] parent;
public int countComponents(int n, int[][] edges) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
for (int i = 0; i < edges.length; i++) {
union(edges[i][0], edges[i][1]);
}
Set<Integer> hs = new HashSet<>();
for (int i = 0; i < n; i++) {
hs.add(find(parent[i]));
}
return hs.size();
}
private void union(int node1, int node2) {
parent[find(node1)] = find(node2);
}
private int find(int node) {
if (parent[node] == node) {
return node;
}
parent[node] = parent[parent[node]]; // Path compression
return find(parent[node]);
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
int[] parent;
public int countComponents(int n, int[][] edges) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
for (int[] edge : edges) {
int n1 = find(edge[0]);
int n2 = find(edge[1]);
if (n1 != n2) {
n--;
parent[n1] = n2; // Union
}
}
return n;
}
private int find(int node) {
while (node != parent[node]) {
parent[node] = parent[parent[node]]; // Path compression
node = parent[node];
}
return node;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public int longestConsecutive(int[] nums) {
// Code here
}
}
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example,
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums){
set.add(num);
}
int len = 0;
for (int num : nums){
if (!set.contains(num)){
continue;
}
int left = num - 1;
while (set.contains(left)){
set.remove(left);
left--;
}
int right = num + 1;
while (set.contains(right)){
set.remove(right);
right++;
}
len = Math.max(len, right - left - 1);
}
return len;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Example:
Given m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]].
Initially, the 2d grid grid is filled with water.
(Assume 0 represents water and 1 represents land).
0 0 0
0 0 0
0 0 0
Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land.
1 0 0
0 0 0 Number of islands = 1
0 0 0
Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land.
1 1 0
0 0 0 Number of islands = 1
0 0 0
Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land.
1 1 0
0 0 1 Number of islands = 2
0 0 0
Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land.
1 1 0
0 0 1 Number of islands = 3
0 1 0
We return the result as an array: [1, 1, 2, 3]
Can you do it in time complexity O(k log mn), where k is the length
of the positions?
public List<Integer> numIslands2(int m, int n, int[][] positions) {
// Code here
}
A 2d grid map of m rows and n columns is initially filled with water.
We may perform an addLand operation which turns the water at position
(row, col) into a land. Given a list of positions to operate, count
the number of islands after each addLand operation. An island is
surrounded by water and is formed by connecting adjacent lands
horizontally or vertically. You may assume all four edges of the grid
are all surrounded by water.
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public List<Integer> numIslands2(int m, int n, int[][] positions) {
List<Integer> result = new ArrayList<>();
Dot[][] grid = new Dot[m][n]; // 2D grid?
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
grid[i][j] = new Dot(i, j, false);
}
}
int count = 0;
for (int[] po : positions) {
int change = union(grid, po[0], po[1]);
count += change;
result.add(count);
}
return result;
}
private int union(Dot[][] grid, int i, int j) {
Dot curDot = new Dot(i, j, true);
int fatherNumber = 0;
Set<Dot> set = new HashSet<>();
set.add(null);
set.add(findFather(grid, i - 1, j));
set.add(findFather(grid, i + 1, j));
set.add(findFather(grid, i, j - 1));
set.add(findFather(grid, i, j + 1));
int result = 2 - set.size(); // 1 (itself) + 1 (null) - all other merged
for (Dot d : set) {
if (d != null) {
d.father = curDot;
}
}
grid[i][j] = curDot;
return result;
}
private Dot findFather(Dot[][] grid, int i, int j) {
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || !grid[i][j].land) {
return null;
}
Dot d = grid[i][j];
while (!d.father.equals(d)) {
d.father = d.father.father;
d = d.father;
}
return d;
}
class Dot {
int x;
int y;
boolean land;
Dot father;
public Dot (int x, int y, boolean land) {
this.x = x;
this.y = y;
this.land = land;
this.father = this;
}
public boolean equals(Dot d) {
return (d.x == this.x && d.y == this.y);
}
public int hashCode() {
int result = 0;
result += this.x * 37;
result += this.y;
return result;
}
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
int[][] dirs = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
public List<Integer> numIslands2(int m, int n, int[][] positions) {
List<Integer> result = new ArrayList<>();
if(m <= 0 || n <= 0) return result;
int count = 0;
int[] roots = new int[m * n]; // 2D -> 1D
Arrays.fill(roots, -1);
for(int[] p : positions) {
int cur = n * p[0] + p[1];
roots[cur] = cur; // One is it's own root
count++;
for(int[] dir : dirs) {
int x = p[0] + dir[0];
int y = p[1] + dir[1];
int nb = n * x + y;
if(x < 0 || x >= m || y < 0 || y >= n || roots[nb] == -1) {
continue;
}
int rootNb = findIsland(roots, nb); // Find
if(cur != rootNb) {
roots[rootNb] = cur; // Union
count--;
}
}
result.add(count);
}
return result;
}
private int findIsland(int[] roots, int id) {
while(id != roots[id]) {
roots[id] = roots[roots[id]];
id = roots[id];
}
return id;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
11110
11010
11000
00000
Answer: 1
Example 2:
11000
11000
00100
00011
Answer: 3
public int numIslands(char[][] grid) {
// Code here
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
int[][] directions = {{1,0},{-1,0},{0,1},{0,-1}};
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0){
return 0;
}
int M = grid.length;
int N = grid[0].length;
int count = 0;
boolean[][] visited = new boolean[M][N];
for (int i = 0; i < M; i++){
for (int j = 0; j < N; j++){
if (grid[i][j] == '1' && !visited[i][j]){
count++;
dfs(grid, visited, i, j);
}
}
}
return count;
}
public void dfs (char[][] grid, boolean[][] visited, int i, int j){
Queue<Pair> queue = new LinkedList<Pair>();
queue.offer(new Pair(i,j));
visited[i][j] = true;
while (!queue.isEmpty()){
Pair cur = queue.poll();
for (int k = 0; k < 4; k++){
int x = cur.x + directions[k][0];
int y = cur.y + directions[k][1];
if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length
|| grid[x][y] == '0' || visited[x][y]){
continue;
}
queue.offer(new Pair(x,y));
visited[x][y] = true;
}
}
}
public class Pair{
int x;
int y;
public Pair(int x, int y){
this.x = x;
this.y = y;
}
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public int numIslands(char[][] grid) {
if (grid.length == 0 || grid[0].length == 0) {
return 0;
}
int result = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == '1') {
result++;
destroyIsland(grid, i, j);
}
}
}
return result;
}
private void destroyIsland(char[][] grid, int i, int j) {
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0') {
return;
}
grid[i][j] = '0';
destroyIsland(grid, i - 1, j);
destroyIsland(grid, i + 1, j);
destroyIsland(grid, i, j - 1);
destroyIsland(grid, i, j + 1);
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Input: Graph (Nodes and Edges)
Undirected Graph
Copyright © 直通硅谷
http://www.zhitongguigu.com/
The graph shown to the left has many valid topological sorts, including:
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Given an directed graph, a topological order of the graph nodes is defined as follow:
For each directed edge A -> B in graph, A must before B in the order list.
The first node in the order can be any node in the graph with no nodes direct to it.
Find any topological order for the given graph.
// Definition for Directed graph.
class DirectedGraphNode {
int label;
ArrayList<DirectedGraphNode> neighbors;
DirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<DirectedGraphNode>();
}
};
5, 4, 2, 0, 3, 1
5, 2, 3, 4, 1, 0
BFS & DFS
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public ArrayList<DirectedGraphNode> tSort(ArrayList<DirectedGraphNode> graph) {
ArrayList<DirectedGraphNode> result = new ArrayList<>();
Map<DirectedGraphNode, Integer> indegree = new HashMap<>();
LinkedList<DirectedGraphNode> queue = new LinkedList<>();
for (DirectedGraphNode node : graph) {
for (DirectedGraphNode ne : node.neighbors) {
if (!indegree.containsKey(ne)) {
indegree.put(ne, 0);
}
indegree.put(ne, indegree.get(ne) + 1);
}
}
for (DirectedGraphNode node : graph) {
if (!indegree.containsKey(node)) {
queue.offer(node);
}
}
while (!queue.isEmpty()) {
DirectedGraphNode node = queue.poll();
result.add(node);
for (DirectedGraphNode ne : node.neighbors) {
if (indegree.get(ne) == 1) {
queue.offer(ne);
} else {
indegree.put(ne, indegree.get(ne) - 1);
}
}
}
return result;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
For example:
2, [[1,0]]
There are a total of 2 courses to take.
To take course 1 you should have finished course 0.
So it is possible.
2, [[1,0],[0,1]]
There are a total of 2 courses to take.
To take course 1 you should have finished course 0,
and to take course 0 you should also have finished
course 1. So it is impossible.
There are a total of n courses you have to take, labeled from 0 to n - 1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int n = prerequisites.length;
int count = 0;
LinkedList<Integer> queue = new LinkedList<>();
Map<Integer, ArrayList<Integer>> edges = new HashMap<>();
int[] indegrees = new int[numCourses];
for (int i = 0; i < n; i++) {
int from = prerequisites[i][1];
int to = prerequisites[i][0];
if (!edges.containsKey(from)) {
edges.put(from, new ArrayList<Integer>());
}
edges.get(from).add(to);
indegrees[to]++;
}
for (int i = 0; i < numCourses; i++) {
if (indegrees[i] == 0) {
queue.offer(i);
}
}
while (!queue.isEmpty()) {
ArrayList<Integer> edgeList = edges.get(queue.poll());
count++;
for (int i = 0; edgeList != null && i < edgeList.size(); i++) {
indegrees[edgeList.get(i)]--;
if (indegrees[edgeList.get(i)] == 0) {
queue.offer(edgeList.get(i));
}
}
}
return count == numCourses;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
5: [2, 0]
4: [0, 1]
2: [3]
0: null
1: null
3: [1]
0: 2
1: 2
2: 1
3: 1
4: 0
5: 0
BFS & DFS
Copyright © 直通硅谷
http://www.zhitongguigu.com/
There is a new alien language which uses the latin alphabet.
However, the order among letters are unknown to you. You
receive a list of words from the dictionary, where words
are sorted lexicographically by the rules of this new
language. Derive the order of letters in this language.
For example, Given the following words in dictionary,
[
"wrt",
"wrf",
"er",
"ett",
"rftt"
]
The correct order is: "wertf".
Note:
1. You may assume all letters are in lowercase.
2. If the order is invalid, return an empty string.
3. There may be multiple valid order of letters,
return any one of them is fine.
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public String alienOrder(String[] words) {
HashSet<Character>[] edges = new HashSet[26];
int[] indegree = new int[26];
int degreeSize = fillIndegree(words, indegree);
for (int i = 1; i < words.length; i++) {
String s1 = words[i - 1];
String s2 = words[i];
for (int j = 0; j < Math.min(s1.length(), s2.length()); j++) {
if (s1.charAt(j) != s2.charAt(j)) {
char from = s1.charAt(j), to = s2.charAt(j);
edges[from - 'a'] = (edges[from - 'a'] == null) ?
new HashSet<Character>() : edges[from - 'a'];
if (edges[from - 'a'].add(to)) {
indegree[to - 'a']++;
}
break;
}
}
}
LinkedList<Integer> queue = new LinkedList<>();
for (int i = 0; i < indegree.length; i++) {
if (indegree[i] == 0) {
queue.offer(i);
}
}
StringBuilder sb = new StringBuilder();
while (!queue.isEmpty()) {
int charNum = queue.poll();
sb.append(toChar(charNum));
degreeSize--;
if (edges[charNum] != null) {
for (Character c : edges[charNum]) {
if (--indegree[c - 'a'] == 0) {
queue.offer((int)c - 'a');
}
}
}
}
return degreeSize == 0 ? sb.toString() : "";
}
private char toChar(int i) {
char c = (char)(i + 'a');
return c;
}
private int fillIndegree(String[] words, int[] res) {
int size = 0;
Arrays.fill(res, -1);
for (String s : words) {
for (Character c : s.toCharArray()) {
if (res[c - 'a'] == -1) {
size++;
res[c - 'a'] = 0;
}
}
}
return size;
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
public class Solution {
public String alienOrder(String[] words) {
Map<Character, Integer> indegree = new HashMap<>();
Map<Character, Set<Character>> edges = new HashMap<>();
for (String s : words) {
for (Character c : s.toCharArray()) {
indegree.put(c, 0);
}
}
int charSize = indegree.size();
for (int i = 1; i < words.length; i++) {
String s1 = words[i - 1];
String s2 = words[i];
for (int j = 0; j < Math.min(s1.length(), s2.length()); j++) {
if (s1.charAt(j) != s2.charAt(j)) {
Character from = s1.charAt(j), to = s2.charAt(j);
if (!edges.containsKey(from)) {
edges.put(from, new HashSet<Character>());
}
if (edges.get(from).add(to)) {
indegree.put(to, indegree.get(to) + 1);
}
break;
}
}
}
LinkedList<Character> queue = new LinkedList<>();
for (Map.Entry<Character, Integer> en : indegree.entrySet()) {
if (en.getValue() == 0) {
queue.offer(en.getKey());
}
}
StringBuilder sb = new StringBuilder();
while (!queue.isEmpty()) {
Character c = queue.poll();
sb.append(c);
charSize--;
if (edges.containsKey(c)) {
for (Character to : edges.get(c)) {
indegree.put(to, indegree.get(to) - 1);
if (indegree.get(to) == 0) {
queue.offer(to);
}
}
}
}
return charSize == 0 ? sb.toString() : "";
}
}
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Input: Graph (Nodes & Edges)
Directed Graph
Copyright © 直通硅谷
http://www.zhitongguigu.com/
Union Find
Examples
Topological Sort
Examples (DFS)
Course Schedule II (One answer)
Course Schedule III (All possible answers)