Copyright © 直通硅谷 

http://www.zhitongguigu.com/

Union Find

Topological Sort

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.

  • Find: Determine which subset a particular element is in. Find typically returns an item from this set that serves as its "representative"; by comparing the result of two Find operations, one can determine whether two elements are in the same subset. (Find Parent)
  • Union: Join two subsets into a single subset. (Join Parents)

Connected Components in an Undirected Graph

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
}

Connected Components in an Undirected Graph

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]);
    }
}

Connected Components in an Undirected Graph

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]);
    }
}

Connected Components in an Undirected Graph

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;
    }
}

Longest Consecutive Sequence

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.

Longest Consecutive Sequence

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;
    }
}

Number of Islands II

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;
    }
}

Number of Islands

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    
}

Number of Islands

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;
       }
   } 
}

Number of Islands

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/

Union Find Summary

Input: Graph (Nodes and Edges)

Undirected Graph

  1. Each Node has a parent
  2. For all the edges, find two parents
  3. Union two parents into one
  4. Count # of parents

Copyright © 直通硅谷 

http://www.zhitongguigu.com/

Topological Sort

The graph shown to the left has many valid topological sorts, including:

  • 5, 7, 3, 11, 8, 2, 9, 10 (visual left-to-right, top-to-bottom)
  • 3, 5, 7, 8, 11, 2, 9, 10 (smallest-numbered available vertex first)
  • 5, 7, 3, 8, 11, 10, 9, 2 (fewest edges first)
  • 7, 5, 11, 3, 10, 8, 9, 2 (largest-numbered available vertex first)
  • 5, 7, 11, 2, 3, 8, 9, 10 (attempting top-to-bottom, left-to-right)
  • 3, 7, 8, 5, 11, 10, 2, 9 (arbitrary)

Copyright © 直通硅谷 

http://www.zhitongguigu.com/

Topological Sort

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/

Topological Sort

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/

Course Schedule

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/

Course Schedule

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/

Topological Sort

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/

Alien Dictionary

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/

Aline Dictionary

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/

Aline Dictionary

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/

Topological Sort

Input: Graph (Nodes & Edges)

Directed Graph

  1. Map each node, with it's to list
  2. For each node, save it's indegree
  3. Maintain a queue of 0 indegree
  4. Nodes polled from queue is ~

Copyright © 直通硅谷 

http://www.zhitongguigu.com/

Homework

Union Find

Examples

Surrounded Regions

Topological Sort

Examples (DFS)

Course Schedule II (One answer)

Course Schedule III (All possible answers)

Longest Increasing Path in a Matrix

[GoValley-201612] Union Find, Topological Sort

By govalley201612

[GoValley-201612] Union Find, Topological Sort

Introduction to GoValley

  • 836