Showing posts with label UnionFind. Show all posts
Showing posts with label UnionFind. Show all posts

Thursday, February 7, 2019

765. Couples Holding Hands

765Couples Holding Hands
N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum number of swaps so that every couple is sitting side by side. A swap consists of choosing any two people, then they stand up and switch seats.
The people and seats are represented by an integer from 0 to 2N-1, the couples are numbered in order, the first couple being (0, 1), the second couple being (2, 3), and so on with the last couple being (2N-2, 2N-1).
The couples' initial seating is given by row[i] being the value of the person who is initially sitting in the i-th seat.
Example 1:
Input: row = [0, 2, 1, 3]
Output: 1
Explanation: We only need to swap the second (row[1]) and third (row[2]) person.
Example 2:
Input: row = [3, 2, 0, 1]
Output: 0
Explanation: All couples are already seated side by side.
Note:
  1. len(row) is even and in the range of [4, 60].
  2. row is guaranteed to be a permutation of 0...len(row)-1.
---------------------------
贪心,本质上Cycle Finding或union find
ref: https://leetcode.com/problems/couples-holding-hands/discuss/113362/JavaC++-O(N)-solution-using-cyclic-swapping

class Solution {
    public int minSwapsCouples(int[] row) {
        Map<Integer, Integer> valueToIndex = new HashMap<>();
        
        for (int i = 0; i < row.length; i++) {
            valueToIndex.put(row[i], i);
        }
        
        int swaps = 0;
        for (int i = 0; i < row.length; i += 2) {
            int p1 = row[i];
            int p2 = (p1 % 2) == 0 ? p1 + 1 : p1 - 1;
            
            if (row[i + 1] != p2) {
                int p2Index = valueToIndex.get(p2);
                valueToIndex.put(p2, i + 1);
                valueToIndex.put(row[i + 1], p2Index);
                swap(row, p2Index, i + 1);
                swaps++;
            }
        }
        
        return swaps;
    }
    
    private void swap(int[] row, int i1, int i2) {
        int tmp = row[i1];
        row[i1] = row[i2];
        row[i2] = tmp;
    }
}

Friday, January 25, 2019

261. Graph Valid Tree

261Graph Valid Tree
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 check whether these edges make up a valid tree.
Example 1:
Input: n = 5, and edges = [[0,1], [0,2], [0,3], [1,4]]
Output: true
Example 2:
Input: n = 5, and edges = [[0,1], [1,2], [2,3], [1,3], [1,4]]
Output: false
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.
--------------------
树的条件:
1. 没环
2. 所有的node都是连接在一起
class Solution {
    public boolean validTree(int n, int[][] edges) {
        int[] nums = new int[n];
        int[] sizes = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = i;
            sizes[i] = 1;
        }
        
        for (int[] e : edges) {
            int root1 = find(nums, e[0]);
            int root2 = find(nums, e[1]);
            if (root1 == root2) return false;
            
            if (sizes[root1] > sizes[root2]) {
                nums[root2] = root1;    
            }else {
                nums[root1] = root2;    
            }
        }
        
        int root = find(nums,0);
        for (int i = 1; i < n; i++) {
            if (root != find(nums, i)) return false;
        }
        
        return true;
    }
    
    private int find(int[] nums, int i) {
        while (i != nums[i]) {
            i = nums[i];
        }
        
        return i;
    }
    
    
}

Friday, December 28, 2018

684. 685. Redundant Connection, Redundant Connection II

684Redundant Connection
In this problem, a tree is an undirected graph that is connected and has no cycles.
The given input is a graph that started as a tree with N nodes (with distinct values 1, 2, ..., N), with one additional edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed.
The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] with u < v, that represents an undirected edge connecting nodes u and v.
Return an edge that can be removed so that the resulting graph is a tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array. The answer edge [u, v] should be in the same format, with u < v.
Example 1:
Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given undirected graph will be like this:
  1
 / \
2 - 3
Example 2:
Input: [[1,2], [2,3], [3,4], [1,4], [1,5]]
Output: [1,4]
Explanation: The given undirected graph will be like this:
5 - 1 - 2
    |   |
    4 - 3
Note:





  • The size of the input 2D-array will be between 3 and 1000.
  • Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.


  • Update (2017-09-26):
    We have overhauled the problem description + test cases and specified clearly the graph is an undirected graph. For the directedgraph follow up please see Redundant Connection II). We apologize for any inconvenience caused.
    -----------------------
    Union Find. DFS 也可以做,只是题意要求返回在原数组里最靠后的一位,所以UF更简单
    class Solution {
        public int[] findRedundantConnection(int[][] edges) {
            int n = edges.length;
            int[] ids = new int[n + 1];
            int[] sizes = new int[n + 1];
            
            for (int i = 1; i <= n; i++) {
                ids[i] = i;
                sizes[i] = 1;
            }
            
            for (int[] e : edges) {
                int r1 = find(ids, e[0]);
                int r2 = find(ids, e[1]);
                if (r1 == r2) return e;
                
                union(r1,r2,ids,sizes);
            }
            
            return null;
        }
        
        private void union(int id1, int id2, int[] ids, int[] sizes) {
            if (sizes[id1] > sizes[id2]) {
                sizes[id1] += sizes[id2];
                ids[id2] = id1;
            }else {
                sizes[id2] += sizes[id1];
                ids[id1] = id2;
            }
        }
        
        private int find(int[] ids, int id) {
            while (ids[id] != id) {
                ids[id] = ids[ids[id]];
                id = ids[id];
            }
            
            return id;
        }
    }
    

    685Redundant Connection II
    In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.
    The given input is a directed graph that started as a rooted tree with N nodes (with distinct values 1, 2, ..., N), with one additional directed edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed.
    The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] that represents a directed edge connecting nodes u and v, where u is a parent of child v.
    Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.
    Example 1:
    Input: [[1,2], [1,3], [2,3]]
    Output: [2,3]
    Explanation: The given directed graph will be like this:
      1
     / \
    v   v
    2-->3
    
    Example 2:
    Input: [[1,2], [2,3], [3,4], [4,1], [1,5]]
    Output: [4,1]
    Explanation: The given directed graph will be like this:
    5 <- 1 -> 2
         ^    |
         |    v
         4 <- 3
    
    Note:


  • The size of the input 2D-array will be between 3 and 1000.
  • Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.
  • -----------------------
    因为是tree + 1个extra edge,所以分2种情况:
    1. 所有的结点都有parent(包括root)。这有个环。
    2. 有一个结点有2个parent指向。这里还可以分2种情况。

    思路是先确定是哪种情况,2的话找出那2个parent的指向,然后断开第2个。进行正常的UF操作,如果碰到是2的情况,那说明先前存的第1个parent指向是extra edge。如果碰到的都是是1的情况,则当前的edge是多余。

    如果没有相同的父节点,说明之前断开第2个edge是多余的(环被打断)

    同样的,这题可以用DFS做,也得先preprocess


    class Solution {
        public int[] findRedundantDirectedConnection(int[][] edges) {
            int n = edges.length;
            int[] ids = new int[n + 1];
            int[][] cands = new int[2][2];
            
            for (int[] e : edges) {            
                if (ids[e[1]] != 0) {
                    cands[0] = new int[]{ids[e[1]], e[1]};
                    cands[1] = new int[]{e[0], e[1]};
                    e[0] = 0;
                }else {
                    ids[e[1]] = e[0];    
                }
            }
            
            for (int i = 1; i <= n; i++) 
                ids[i] = i;
            
            for (int[] e : edges) {
                if (e[0] == 0) continue;
                int r1 = find(ids, e[0]);
                int r2 = e[1];
                if (r1 == r2) {
                    if (cands[0][0] == 0) return e;
                    return cands[0];
                }
                
                ids[r2] = r1;
            }
            
            return cands[1];
        }
        
        private int find(int[] ids, int id) {
            while (ids[id] != id) {
                ids[id] = ids[ids[id]];
                id = ids[id];
            }
            
            return id;
        }
    }
    

    Sunday, September 9, 2018

    399. Evaluate Division

    399Evaluate Division
    Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.
    Example:
    Given a / b = 2.0, b / c = 3.0.
    queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? .
    return [6.0, 0.5, -1.0, 1.0, -1.0 ].
    The input is: vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries, where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector<double>.
    According to the example above:
    equations = [ ["a", "b"], ["b", "c"] ],
    values = [2.0, 3.0],
    queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]. 
    The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.
    ----------------------
    Solution #1, Graph dfs
    O(n * m), n是graph大小,m是query的数量,应该可以用union-find来优化
    class Solution {
        class Node {
            public String key;
            public Map<Node, Double> neighbors;
            public Node(String key) {
                this.key = key;
                neighbors = new HashMap<>();
            }
        }
        
        public double[] calcEquation(String[][] equations, double[] values, String[][] queries) {
            Map<String, Node> graph = buildGraph(equations, values);
            
            int n = queries.length;
            double[] rt = new double[n];
            
            for (int i = 0; i < queries.length; i++) {
                rt[i] = dfs(graph, queries[i][0], queries[i][1], 1.0, new HashSet<String>());
            }
            
            return rt;
        }
        
        private double dfs(Map<String, Node> graph, String start, String end, double value, Set<String> visited) {
            if (!graph.containsKey(start) || !graph.containsKey(end) || visited.contains(start)) return -1.0;
            if (start.equals(end)) return value;
            
            visited.add(start);
            for (Map.Entry<Node, Double> entry : graph.get(start).neighbors.entrySet()) {
                double rt = dfs(graph, entry.getKey().key, end, value * entry.getValue(), visited);
                if (rt != -1.0) return rt;    
                
            }
            
            return -1.0;
        }
        
        private Map<String, Node> buildGraph(String[][] equations, double[] values) {
            Map<String, Node> graph = new HashMap<>();
            
            for (int i = 0; i < equations.length; i++) {
                String[] pair = equations[i];
                if (!graph.containsKey(pair[0])) {
                    Node node = new Node(pair[0]);
                    graph.put(pair[0], node);
                }
                
                if (!graph.containsKey(pair[1])) {
                    Node node = new Node(pair[1]);
                    graph.put(pair[1], node);
                }
                
                graph.get(pair[0]).neighbors.put(graph.get(pair[1]), values[i]);
                graph.get(pair[1]).neighbors.put(graph.get(pair[0]), 1 / values[i]);
            }
            
            return graph;
        }
    }
    

    Solution #2, Union Find,用被除数当作parent
    ToDo: 加入UF本身的优化:size based

    class Solution {
        
        class Node {
            public String key;
            public double val;
            public Node(String key) {
                this.key = key;
                val = 1;
            }
            
            public Node(String key, double val) {
                this.key = key;
                this.val = val;
            }
        }
        
        public double[] calcEquation(String[][] equations, double[] values, String[][] queries) {
            
            Map<String, Node> map = new HashMap<>();
            Map<String, String> uf = new HashMap<>();
            for (int i = 0; i < equations.length; i++) {
                String[] pair = equations[i];
                if (!map.containsKey(pair[0])) {
                    map.put(pair[0], new Node(pair[0]));
                    uf.put(pair[0], pair[0]);
                }
    
                if (!map.containsKey(pair[1])) {
                    map.put(pair[1], new Node(pair[1]));
                    uf.put(pair[1], pair[1]);
                }
    
                Node parentOf1 = find(uf, map, pair[0]);
                Node parentOf2 = find(uf, map, pair[1]);
    
                if (!parentOf1.key.equals(parentOf2.key)) {
                    uf.put(parentOf2.key, parentOf1.key);
                    map.get(parentOf2.key).val = values[i] * parentOf1.val / parentOf2.val;
                }
            }
    
            double[] rt = new double[queries.length];
            for (int i = 0; i < queries.length; i++) {
                if (!map.containsKey(queries[i][0]) || !map.containsKey(queries[i][1])) {
                    rt[i] = -1.0;
                    continue;
                }
    
                Node p1 = find(uf, map, queries[i][0]);
                Node p2 = find(uf, map, queries[i][1]);
                if (p1.key.equals(p2.key)) {
                    rt[i] = p2.val / p1.val;
                }else {
                    rt[i] = -1.0;
                }
            }
    
            return rt;
        }
            
        private Node find(Map<String, String> uf, Map<String, Node> map, String key) {
            String ori = key;
            double val = map.get(ori).val;
    
            while (!uf.get(key).equals(key)) {
                val *= map.get(uf.get(key)).val;
                key = uf.get(key);
            }
    
            uf.put(ori, key);
            map.get(ori).val = val;
            return new Node(key, val); // Use Node as Pair: return the key of parent, but the value of the original passed in key
        }
    }
    

    Thursday, June 28, 2018

    721 Accounts Merge

    721Accounts Merge
    Given a list accounts, each element accounts[i] is a list of strings, where the first element accounts[i][0] is a name, and the rest of the elements are emails representing emails of the account.
    Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.
    After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.
    Example 1:
    Input: 
    accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]]
    Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'],  ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]]
    Explanation: 
    The first and third John's are the same person as they have the common email "johnsmith@mail.com".
    The second John and Mary are different people as none of their email addresses are used by other accounts.
    We could return these lists in any order, for example the answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'], 
    ['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted.
    
    Note:




  • The length of accounts will be in the range [1, 1000].
  • The length of accounts[i] will be in the range [1, 10].
  • The length of accounts[i][j] will be in the range [1, 30].
  • ---------------------------------
    Union Find
    最后返回的时候繁琐了一点,因为题目要求sort过,跟名字一定要在第一位。
    Todo:分析复杂度
    class Solution {
        public List<List<String>> accountsMerge(List<List<String>> accounts) {
            Map<String, Integer> m = new HashMap<>();
            int n = accounts.size();
            int[] uf = getUF(n);
            
            for (int i = 0; i < accounts.size(); i++) {
    
                List<String> row = accounts.get(i);
                for (int j = 1; j < row.size(); j++) {
                    String email = row.get(j);
                    
                    if (m.containsKey(email) && getRoot(uf, m.get(email)) != getRoot(uf, i)) {
                        int index = m.get(email);
                        uf[getRoot(uf, uf[i])] = getRoot(uf, index);
                        n--;
                    }else {
                        m.put(email, getRoot(uf, i));
                    }
                }
            }
            
            return sortAndReturn(m, uf);
        }
        
        private List<List<String>> sortAndReturn(Map<String, Integer> m, int[] uf) {
            Map<Integer,List<String>> rt = new HashMap<>();
            for (Map.Entry<String, Integer> entry : m.entrySet()) {
                int index = getRoot(uf, entry.getValue());
                if (!rt.containsKey(index)) {
                    rt.put(index, new ArrayList<String>());    
                }
                rt.get(index).add(entry.getKey());
            }
            
            List<List<String>> ret= new ArrayList<>();
            for (List<String> l : rt.values()) {
                List<String> temp = new ArrayList<>(l);
                Collections.sort(temp);
                String name = accounts.get(getRoot(uf, m.get(temp.get(0)))).get(0);
                temp.add(0, name);
                ret.add(temp);
            }
            
            return ret;
        }
        
        private int getRoot(int[] uf, int index) {
            
            while (uf[index] != index) {
                index = uf[index];
                uf[index] = uf[uf[index]];
            }
            
            return index;
        }
        
        private int[] getUF(int n) {
            int[] rt = new int[n];
            for (int i = 0; i < n; i++) {
                rt[i] = i;
            }
            
            return rt;
        }
    }
    

    ToDo, DFS做法,见https://leetcode.com/problems/accounts-merge/solution/

    Saturday, November 14, 2015

    Day 134, #302 #305 Smallest Rectangle Enclosing Black Pixels, Number of Islands II

    Smallest Rectangle Enclosing Black Pixels
    An image is represented by a binary matrix with 0 as a white pixel and 1 as a black pixel. The black pixels are connected, i.e., there is only one black region. Pixels are connected horizontally and vertically. Given the location (x, y) of one of the black pixels, return the area of the smallest (axis-aligned) rectangle that encloses all black pixels.
    For example, given the following image:
    [
      "0010",
      "0110",
      "0100"
    ]
    
    and x = 0y = 2,
    Return 6.
    ----------------------------------------------------------------------
    COME_BACK, mid的取值问题
    binary search
    getTop()和getLeft() 返回的都是包含black,其他2个返回的是不包含black。
    稍微简单一点写法:https://leetcode.com/discuss/68246/c-java-python-binary-search-solution-with-explanation
    class Solution {
    public:
        int getTop(vector<vector<char>>& image, int x) {
            int top = 0, bottom = x, n = image[0].size();
            
            while (top < bottom) {
                int mid = (top + bottom) / 2;
                int k = 0;
                while (k < n && image[mid][k] == '0') {
                    k++;
                }
                
                if (k < n) {
                    bottom = mid;
                }else {
                    top = mid + 1;
                }
            }
            
            return bottom;
        }
        
        int getBottom(vector<vector<char>>& image, int x) {
            int top = x, bottom = image.size(), n = image[0].size();
            
            while (top < bottom) {
                int mid = (top + bottom) / 2;
                int k = 0;
                while (k < n && image[mid][k] == '0') {
                    k++;
                }
                
                if (k < n) {
                    top = mid + 1;
                }else {
                    bottom = mid;
                }
            }
            
            return bottom;
        }
        
        int getLeft(vector<vector<char>>& image, int y) {
            int left = 0, right = y, m = image.size();
            
            while (left < right) {
                int mid = (left + right) / 2;
                int k = 0;
                while (k < m && image[k][mid] == '0') {
                    k++;
                }
                
                if (k < m) {
                    right = mid;
                }else {
                    left = mid + 1;
                }
            }
            return left;
        }
        
        int getRight(vector<vector<char>>& image, int y) {
            int right = image[0].size(), left = y, m = image.size();
            while (left < right) {
                int mid = (left + right) / 2;
                int k = 0;
                while (k < m && image[k][mid] == '0') {
                    k++;
                }
                
                if (k < m) {
                    left = mid + 1;
                }else {
                    right = mid;
                }
            }
            
            return left;
        }
    
        int minArea(vector<vector<char>>& image, int x, int y) {
            int top = getTop(image,x);
            int bottom = getBottom(image,x + 1);
            int left = getLeft(image,y);
            int right = getRight(image,y + 1);
            
            return (bottom - top) * (right - left);
        }
    };
    

    Number of Islands II
    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.
    Example:
    Given m = 3, n = 3positions = [[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]
    Challenge:
    Can you do it in time complexity O(k log mn), where k is the length of the positions?
    -------------------------------------------------------
    COME_BACK
    标准union find, O(k * lg k), k 为 0 - m * n
    注意:
    #1 2维坐标和1维的来回转换
    #2 看清题意,对count的计算
    class UnionFind {
    public:
        UnionFind(vector<pair<int, int>>& positions, int col) {
            this->col = col;
            count = 0;
        }
        
        void addPoint(pair<int,int> &p) {
            int index = encode(p);
            root[index] = index;
            size[index] = 1;
            count++;
        }
     
        int findRoot(pair<int,int> &p) {
            int index = encode(p);
            if (root.find(index) == root.end()) return -1;
            
            while (root[index] != index) {
                index = root[index];
            }
            return index;
        }
    
        void unionF(pair<int,int> &p1, pair<int,int> &p2) {
            int root1 = findRoot(p1), root2 = findRoot(p2);
            if (root1 == root2) return;
            
            if (size[root1] > size[root2]) {
                size[root1] += size[root2];
                root[root2] = root1;
            }else {
                root[root1] = root2;
            }
            count--;
        }
        
        int getCount() {
            return count;
        }
    
    private:
        unordered_map<int,int> root;
        unordered_map<int,int> size;
        int count;
        int col;
        
        int encode(pair<int, int> &position) {
            return position.first * col + position.second;
        }
        
        pair<int,int> decode(int index) {
            return make_pair<int,int>(index / col, index % col);
        }
    };
    
    class Solution {
    public:
        vector<int> numIslands2(int m, int n, vector<pair<int, int>>& positions) {
            vector<int> rt;
            UnionFind uf(positions, n);
            
            for (int i = 0; i < positions.size(); i++) {
                uf.addPoint(positions[i]);
                int x = positions[i].first, y = positions[i].second;
                pair<int,int> p = make_pair(x + 1, y);
                if (x + 1 < m && uf.findRoot(p) != - 1) {
                    uf.unionF(positions[i], p);
                }
                
                p = make_pair(x - 1,y);
                if (x - 1 >= 0 && uf.findRoot(p) != - 1) {
                    uf.unionF(positions[i], p);
                }
                
                p = make_pair(x, y + 1);
                if (y + 1 < n && uf.findRoot(p) != - 1) {
                    uf.unionF(positions[i],p);
                }
                
                p = make_pair(x, y - 1);
                if (y - 1 >= 0 && uf.findRoot(p) != - 1) {
                    uf.unionF(positions[i], p);
                }
                rt.push_back(uf.getCount());
            }
            
            return rt;
        }
    };
    

    Java, ids类似于一个树。注意2处可以优化的地方。 O(k * log m * n), k为插入的次数,log(m*n)为树的深度(find()方法),完全优化后深度为1
    https://blog.csdn.net/dm_vincent/article/details/7655764
    https://blog.csdn.net/dm_vincent/article/details/7769159 UnionFind更多应用
     
    class Solution {
        
        private int[][] dirs = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};
        
        public List numIslands2(int m, int n, int[][] positions) {
            List rt = new ArrayList<>();
            UnionFind uf = new UnionFind(m,n);
            
            for (int[] pos : positions) {
                uf.add(pos);
                int p = uf.getRootId(pos[0], pos[1]);
                for (int[] dir : dirs) {
                    int i = pos[0] + dir[0];
                    int j = pos[1] + dir[1];
                    int q = uf.getRootId(i, j);
                    if (q > 0 && q != p) {
                        uf.union(pos[0], pos[1], i, j);
                    }
                }   
                
                rt.add(uf.getCount());
            }
            
            return rt;
        }
    }
    
    class UnionFind {
        
        private int count;
        private int[] ids;
        private int[] sizes;
        private int m;
        private int n;
        
        public UnionFind(int m, int n) {
            count = 0;
            ids = new int[m * n + 1];
            sizes = new int[m * n + 1];
            this.m = m;
            this.n = n;
        }
        
        public int getRootId(int i, int j) {
            if (i >= 0 && i < m && j >= 0 && j < n) {
                int index = getIndex(i,j);
                if ((ids[index]) == 0) return 0;
                return find(i, j);
            }
            
            return 0;
        }
        
        public void add(int[] pos) {
            int id = getIndex(pos[0], pos[1]);
            ids[id] = id;
            sizes[id] = 1;
            count++;
        }
        
        public int find(int i, int j) {
            int id = getIndex(i,j);
            while (ids[id] != id) {
                ids[id] = ids[ids[id]]; // Optimization
                id = ids[id];
            }
            
            return id;
        }
        
        public void union(int pI, int pJ, int qI, int qJ) {
            int rootP = find(pI, pJ);
            int rootQ = find(qI, qJ);
            
            if (rootP == rootQ) return;
            
            if (sizes[rootP] >= sizes[rootQ]) { // Optimization
                sizes[rootP] += sizes[rootQ];
                ids[rootQ] = rootP;    
            }else {
                sizes[rootQ] += sizes[rootP];
                ids[rootP] = rootQ;    
            }
            
            count--;
        }
        
        public int getCount() {
            return count;
        }
        
        private int getIndex(int i, int j) {
            return i * n + j + 1;
        }
    }
    

    Friday, September 4, 2015

    Day 123, #261 #266 #269 #270, Graph Valid Tree, Palindrome Permutation, Alien Dictionary, Closest Binary Search Tree Value

    Graph Valid Tree
    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 check whether these edges make up a valid tree.
    For example:
    Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true.
    Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false.
    Hint:
    1. Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], what should your return? Is this case a valid tree?
    2. According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.”
    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 inedges.
    -------------------------------------------------------------
    找环和联通
    DFS的做法
    出错点:
    #1 如何建立graph
    #2 因为是无向图,参数中要传入parent节点

    class Solution {
    public:
        bool dfs(vector<bool> &visit,vector<vector<int>> &graph,int node,int parent) {
            if (visit[node]) return false;
            visit[node] = true;
            for (int i = 0; i < graph[node].size(); i++) {
                if (graph[node][i] == parent) continue;
                if (!dfs(visit,graph,graph[node][i],node)) return false;
            }
            
            return true;
        }
    
        bool validTree(int n, vector<pair<int, int>>& edges) {
            vector<vector<int>> graph(n,vector<int>());
            for (int i = 0; i < edges.size(); i++) {
                graph[edges[i].first].push_back(edges[i].second);
                graph[edges[i].second].push_back(edges[i].first);
            }
            
            vector<bool> visit(n,false);
            if (!dfs(visit,graph,0,0)) return false;
            
            for (int i = 0; i < n; i++) {
                if (!visit[i]) return false;
            }
            
            return true;
        }
    };
    

    union find的方法
    http://blog.csdn.net/dm_vincent/article/details/7655764
    class UnionFind {
    public:
        UnionFind(int n) {
            for (int i = 0; i < n; i++) {
                parent.push_back(i);
                size.push_back(1);
            }
            count = n;
        }
        int find(int num) {
            while (num != parent[num]) {
                num = parent[num];
            }
            return num;
        }
        
        void do_union(int num1,int num2) {
            int f1 = find(num1),f2 = find(num2);
            if (f1 == f2) return;
            if (size[f1] > size[f2]) {
                size[f1] += size[f2];
                parent[f2] = f1;
            }else {
                size[f2] += size[f1];
                parent[f1] = f2;
            }
            count--;
        }
        
        bool isTree() {
            return count == 1;
        }
        
    private:
        vector<int> parent;
        vector<int> size;
        int count;
    };
    
    class Solution {
    public:
        bool validTree(int n, vector<pair<int, int>>& edges) {
            UnionFind uf(n);
            for (int i = 0; i < edges.size(); i++) {
                if (uf.find(edges[i].first) == uf.find(edges[i].second)) {
                    return false;
                }
                uf.do_union(edges[i].first,edges[i].second);
            }
            
            return uf.isTree();
        }
    };
    

    Palindrome Permutation
    Given a string, determine if a permutation of the string could form a palindrome.
    For example,
    "code" -> False, "aab" -> True, "carerac" -> True.
    Hint:
    1. Consider the palindromes of odd vs even length. What difference do you notice?
    2. Count the frequency of each character.
    3. If each character occurs even number of times, then it must be a palindrome. How about character which occurs odd number of times?
    ----------------------------------------------------------------------
    class Solution {
    public:
        bool canPermutePalindrome(string s) {
            vector<bool> alph(256,false);
            int single = 0;
            for (int i = 0; i < s.length(); i++) {
                if(!alph[s[i]]) {
                    single++;
                }else {
                    single--;
                }
                alph[s[i]] = !alph[s[i]];
            }
            
            return single < 2;
        }
    };
    

    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, wherewords 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.
    ------------------------------------------------------------------------------------
    COME_BACK
    出错点:16 - 23行,建graph的时候,要遍历所有string
    graph的形式也可以用set,适合稀疏型

    class Solution {
    public:
        void createGraph(vector<string>& words,vector<vector<bool>> &graph,vector<bool> &exist) {
            words.insert(words.begin(),"");
            for (int i = 1; i < words.size(); i++) {
                int j = 0, k = 0;
                string s1 = words[i - 1],s2 = words[i]; 
                while (j < s1.length() && k < s2.length() && s1[j] == s2[k]) {
                    exist[s1[j] - 'a'] = true;
                    j++;
                    k++;
                }
                if (j < s1.length() && k < s2.length()) {
                    graph[s1[j] - 'a'][s2[k] - 'a'] = true;
                }
                while (j < s1.length()) {
                    exist[s1[j] - 'a'] = true;
                    j++;
                }
                while (k < s2.length()) {
                    exist[s2[k] - 'a'] = true;
                    k++;
                }
            }
        }
    
        void dfs(vector<vector<bool>> &graph,vector<int> &visit,char node,bool &cycle,string &order) {
            if (visit[node - 'a'] == -1) {
                cycle = true;
                return;
            }
            if (visit[node - 'a'] == 1) return;
            
            visit[node - 'a'] = -1;
            for (char i = 'a'; i <= 'z'; i++) {
                if (graph[node - 'a'][i - 'a']) dfs(graph,visit,i,cycle,order);
            }
            
            visit[node - 'a'] = 1;
            order = node + order;
        }
    
        string topSort(vector<vector<bool>> &graph,vector<bool> &exist) {
            vector<int> visit(26,0);
            string order = "";
            bool cycle =false;
            
            for (char i = 'a'; i <= 'z'; i++) {
                if (exist[i - 'a']) dfs(graph,visit,i,cycle,order);
            }
            
            if (cycle) return "";
            return order;
        }
    
        string alienOrder(vector<string>& words) {
            vector<vector<bool>> graph(26,vector<bool>(26,false));
            vector<bool> exist(26,false);
            createGraph(words,graph,exist);
    
            return topSort(graph,exist);
        }
    };
    

    Closest Binary Search Tree Value
    Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.
    Note:
    • Given target value is a floating point.
    • You are guaranteed to have only one unique value in the BST that is closest to the target.
    -----------------------------------------------------------------
    递归,注意传入的cur是pass by reference
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        void helper(TreeNode* root, double target, TreeNode* &cur) {
            if (root == NULL) return;
            if (cur == NULL || abs(root->val - target) < abs(cur->val - target)) {
                cur = root;
            }
            
            if (root->val > target) {
                helper(root->left,target,cur);
            }else if (root->val < target) {
                helper(root->right,target,cur);
            }
        }
    
        int closestValue(TreeNode* root, double target) {
            TreeNode *cur = NULL;
            helper(root,target,cur);
            return cur->val;
        }
    };
    

    遍历
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int closestValue(TreeNode* root, double target) {
            int closest = root->val;
            while (root) {
                if (abs(root->val - target) < abs(closest - target)) {
                    closest = root->val;
                }
                if (root->val < target) {
                    root = root->right;
                }else {
                    root = root->left;
                }
            }
            return closest;
        }
    };