Friday, August 21, 2015

Leetcode: Flatten 2D Vector

Implement an iterator to flatten a 2d vector.
For example,
Given 2d vector =
[
  [1,2],
  [3],
  [4,5,6]
]
By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,2,3,4,5,6].
Hint:
  1. How many variables do you need to keep track?
  2. Two variables is all you need. Try with x and y.
  3. Beware of empty rows. It could be the first few rows.
  4. To write correct code, think about the invariant to maintain. What is it?
  5. The invariant is x and y must always point to a valid point in the 2d vector. Should you maintain your invariant ahead of time or right when you need it?
  6. Not sure? Think about how you would implement hasNext(). Which is more complex?
  7. Common logic in two different places should be refactored into a common method.
Understand the problem:
The question itself is very easy to solve. Just several corner cases need to think of:
  -- What if the 2d vector contains empty arrays, e.g. [ ], [ ], 1 2 3 ? In this case, the next() should not output anything, but the return type is int. There the hasNext() should be more complicated in which it handles this situation. 
  -- What if the 2d vector itself is empty? Again, handle it in hasNext() 

Code (Java):
public class Vector2D {
    
    private List<List<Integer>> vec2d;
    private int rowId;
    private int colId;
    private int numRows;
    
    public Vector2D(List<List<Integer>> vec2d) {
        this.vec2d = vec2d;
        rowId = 0;
        colId = 0;
        numRows = vec2d.size();
    }

    public int next() {
        int ans = 0;
        
        if (colId < vec2d.get(rowId).size()) {
            ans = vec2d.get(rowId).get(colId);
        }
        
        colId++;
        
        if (colId == vec2d.get(rowId).size()) {
            colId = 0;
            rowId++;
        }
        
        return ans;
    }

    public boolean hasNext() {
        while (rowId < numRows && (vec2d.get(rowId) == null || vec2d.get(rowId).isEmpty())) {
            rowId++;
        }
        
        return vec2d != null && 
        !vec2d.isEmpty() &&
        rowId < numRows;
    }
}

/**
 * Your Vector2D object will be instantiated and called as such:
 * Vector2D i = new Vector2D(vec2d);
 * while (i.hasNext()) v[f()] = i.next();
 */


Followup:
As an added challenge, try to code it using only iterators in C++ or iterators in Java.

Code (Java):
public class Vector2D {
    private Iterator<List<Integer>>outerIterator;
    private Iterator<Integer> innerIterator;

    public Vector2D(List<List<Integer>> vec2d) {
        outerIterator = vec2d.iterator();
        innerIterator = Collections.emptyIterator();
    }

    public int next() {
        return innerIterator.next();
    }

    public boolean hasNext() {
        if (innerIterator.hasNext()) {
            return true;
        }
        
        if (!outerIterator.hasNext()) {
            return false;
        }
        
        innerIterator = outerIterator.next().iterator();
        
        
        return hasNext();
    }
}

/**
 * Your Vector2D object will be instantiated and called as such:
 * Vector2D i = new Vector2D(vec2d);
 * while (i.hasNext()) v[f()] = i.next();
 */

Summary:
There are multiple corner cases need to handle:
1. If the 2d vec contains empty vec, e.g. [ ], [ ] , [1, 2], [ ], [ ], [3], we need to handle it in method hasNext();
2. In the method 2 using only the Iterator solution, the innerIterator must be initilized as Collections.emptyIterator() because the method hasNext() first checks if the innerIterator.hasNext(), so the inner iterator itself must be an iterator at first. 


Update on 11/18/15:

public class Vector2D {
    private Iterator<List<Integer>> outer;
    private Iterator<Integer> inner;

    public Vector2D(List<List<Integer>> vec2d) {
        outer = vec2d.iterator();
        inner = Collections.emptyIterator(); //inner = outer.iterator(); wrong: if outer is null, then exception
    }

    public int next() {
        return inner.next();
    }

    public boolean hasNext() {
        if (inner.hasNext()) {
            return true;
        }
        if (!outer.hasNext()) {
            return false;
        }
        inner = outer.next().iterator();
        while(!inner.hasNext() && outer.hasNext()) {
            inner = outer.next().iterator();
        }
        return inner.hasNext();
    }
}

/**
 * Your Vector2D object will be instantiated and called as such:
 * Vector2D i = new Vector2D(vec2d);
 * while (i.hasNext()) v[f()] = i.next();
 */


Thursday, August 20, 2015

Leetcode: Binary Search Tree Iterator

http://buttercola.blogspot.com/2014/12/facebook-binary-tree-iterator.html

Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST.
Calling next() will return the next smallest number in the BST.
Note: next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is the height of the tree.
Code (Java):
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

public class BSTIterator {
    private TreeNode p;
    private Stack<TreeNode> stack = new Stack<TreeNode>();

    public BSTIterator(TreeNode root) {
        this.p = root;
    }

    /** @return whether we have a next smallest number */
    public boolean hasNext() {
        return !stack.isEmpty() || p != null;
    }

    /** @return the next smallest number */
    public int next() {
        while (p != null) {
            stack.push(p);
            p = p.left;
        }
        
        TreeNode curr = stack.pop();
        p = curr.right;
        
        return curr.val;
    }
}

/**
 * Your BSTIterator will be called like this:
 * BSTIterator i = new BSTIterator(root);
 * while (i.hasNext()) v[f()] = i.next();
 */

Update on 5/20/19:
/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 * Example of iterate a tree:
 * BSTIterator iterator = new BSTIterator(root);
 * while (iterator.hasNext()) {
 *    TreeNode node = iterator.next();
 *    do something for node
 * } 
 */


public class BSTIterator {
    private Stack<TreeNode> stack;
    private TreeNode p;
    /*
    * @param root: The root of binary tree.
    */public BSTIterator(TreeNode root) {
        // do intialization if necessary
        this.p = root;
        stack = new Stack<>();
        
        while (p != null) {
            stack.push(p);
            p = p.left;
        }
    }

    /*
     * @return: True if there has next node, or false
     */
    public boolean hasNext() {
        // write your code here
        return !stack.isEmpty();
    }

    /*
     * @return: return next node
     */
    public TreeNode next() {
        // write your code here
        TreeNode ans = stack.pop();
        p = ans.right;
        
        while (p != null) {
            stack.push(p);
            p = p.left;
        }
        
        return ans;
    }
}

Leetcode: Palindrome Permutation

Given a string, determine if a permutation of the string could form a palindrome.
For example,
"code" -> False, "aab" -> True, "carerac" -> True.
Understand the problem:
The problem can be easily solved by count the frequency of each character using a hash map. The only thing need to take special care is consider the length of the string to be even or odd. 
  -- If the length is even. Each character should appear exactly times of 2, e.g. 2, 4, 6, etc..
  -- If the length is odd. One and only one character could appear odd times. 

Code (Java):
public class Solution {
    public boolean canPermutePalindrome(String s) {
        if (s == null || s.length() <= 1) {
            return true;
        }
        
        Map<Character, Integer> map = new HashMap<Character, Integer>();
        
        for (int i = 0; i < s.length(); i++) {
            char letter = s.charAt(i);
            
            if (map.containsKey(letter)) {
                int count = map.get(letter) + 1;
                map.put(letter, count);
            } else {
                map.put(letter, 1);
            }
        }
        
        int tolerance = 0;
        Iterator it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            
            if ((int) pair.getValue() % 2 != 0) {
                tolerance++;
            }
        }
        
        if (s.length() % 2 == 0) {
            return tolerance == 0;
        } else {
            return tolerance == 1;
        }
    }
}

Leetcode: 3Sum Smaller

Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.
For example, given nums = [-2, 0, 1, 3], and target = 2.
Return 2. Because there are two triplets which sums are less than 2:
[-2, 0, 1]
[-2, 0, 3]
Follow up:
Could you solve it in O(n2) runtime?
Understand the problem:
The problem looks quite similar to the 3-sum. Thus we could still sort the array first and use two pointers. 

The only thing needs to take special care of is how to move the pointers. There are two cases to handle: 
  -- If A[i] + A[j] + A[k] < target, which means the numbers between j and k are all less than target, because the array is sorted. Then we move the j pointer forward. 
  -- If A[i] + A[j] + A[k] >= target, we move k pointer backward.

Code (Java):
public class Solution {
    public int threeSumSmaller(int[] nums, int target) {
        if (nums == null || nums.length < 3) {
            return 0;
        }
        
        int result = 0;
        Arrays.sort(nums);
        
        for (int i = 0; i < nums.length - 2; i++) {
            int j = i + 1;
            int k = nums.length - 1;
            while (j < k) {
                if (nums[i] + nums[j] + nums[k] < target) {
                    result += (k - j);
                    j++;
                } else {
                    k--;
                }
            }
        }
        
        return result;
    }
}

Leetcode: Fraction to Recurring Decimal

Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
For example,
  • Given numerator = 1, denominator = 2, return "0.5".
  • Given numerator = 2, denominator = 1, return "2".
  • Given numerator = 2, denominator = 3, return "0.(6)".
Understand the problem:
    0.16  
6 ) 1.00
    0 
    1 0       <-- Remainder=1, mark 1 as seen at position=0.
    - 6 
      40      <-- Remainder=4, mark 4 as seen at position=1.
    - 36 
       4      <-- Remainder=4 was seen before at position=1, so the fractional part which is 16 starts repeating at position=1 => 1(6).
The key insight here is to notice that once the remainder starts repeating, so does the divided result.
You will need a hash table that maps from the remainder to its position of the fractional part. Once you found a repeating remainder, you may enclose the reoccurring fractional part with parentheses by consulting the position from the table.
The remainder could be zero while doing the division. That means there is no repeating fractional part and you should stop right away.
Just like the question Divide Two Integers, be wary of edge case such as negative fractions and nasty extreme case such as -2147483648 / -1.
Code (Java):
public class Solution {
    public String fractionToDecimal(int numerator, int denominator) {
        if (denominator == 0) {
            return "inf";
        }
        
        if (numerator == 0) {
            return "0";
        }
        
        String result = "";
        boolean neg = false;
        
        // Chceck if any negative number
        if ((numerator < 0) ^ (denominator < 0)) {
            neg = true;
        }
        
        // Transform to long to avoid overflow
        long num = numerator;
        long den = denominator;
        
        num = Math.abs(num);
        den = Math.abs(den);
        
        // Get the integer part
        long integer = num / den;
        result = String.valueOf(integer);
        
        // Get the remindar times 10
        long remindar = (num % den) * 10;
        if (remindar == 0) {
            if (neg) {
                return "-" + result;
            } else {
                return result;
            }
        }
        
        Map<Long, Integer> map = new HashMap<Long, Integer>();
        result += ".";
        
        while (remindar != 0) {
            if (map.containsKey(remindar)) {
                int pos = map.get(remindar);
                String part1 = result.substring(0, pos);
                String part2 = result.substring(pos, result.length());
                result = part1 + "(" + part2 + ")";
                
                if (neg) {
                    return "-" + result;
                } else {
                    return result;
                }
            }
            
            result += String.valueOf(remindar / den);
            map.put(remindar, result.length() - 1);
            remindar = (remindar % den) * 10;
        }
        
        if (neg) {
            return "-" + result;
        } else {
            return result;
        }
    }
}

Leetcode: Find Peak Element

A peak element is an element that is greater than its neighbors.
Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.
Note:
Your solution should be in logarithmic complexity.
Understand the problem:
The neighbor of an element A[i] is defined as A[i - 1] and A[i + 1]. Therefore, the peak element is iff A[i] > A[i - 1] && A[i] > A[i + 1]. 

The brute-force solution is quite easy. Just scan and compare. So the time complexity would be O(N). 

However, as is required by the question, the solution should be in O(logn) time. We therefore must think of binary search. 

The idea is: 
  -- If the middle of the array is the peak element, then just return the index. 
  -- If the left neighbor is greater than the middle, move to the left. The peak element must exist in the left half. That is because the num[-1] = num[n] = -inf. 
  -- The same, if the right neighbor is greater than the middle, move to the right. 

Be careful to handle the boundary. Use the binary search template. 

Code (Java):
public class Solution {
    public int findPeakElement(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int lo = 0;
        int hi = nums.length - 1;
        
        while (lo + 1 < hi) {
            int mid = lo + (hi - lo) / 2;
            if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) {
                return mid;
            } else if (nums[mid - 1] > nums[mid]) {
                hi = mid;
            } else if (nums[mid + 1] > nums[mid]) {
                lo = mid;
            }
        }
        
        if (nums[hi] >= nums[lo]) {
            return hi;
        } else {
            return lo;
        }
    }
}

Update on 10/13:15:
public class Solution {
    public int findPeakElement(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int lo = 0;
        int hi = nums.length - 1;
        
        while (lo + 1 < hi) {
            int mid = lo + (hi - lo) / 2;
            
            if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) {
                return mid;
            } else if (nums[mid] < nums[mid - 1]) {
                hi = mid - 1;
            } else if (nums[mid] < nums[mid + 1]) {
                lo = mid + 1;
            }
        }
        
        if (nums[lo] > nums[hi]) {
            return lo;
        } else {
            return hi;
        }
    }
} 

Leetcode: 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.
Understand the problem:
A classic graph search problem. The key is first to transform from the edge list to the adjecent list. The problem is equivalent to whether the graph exists a circle. We could solve the problem by using either DFS or BFS. 

A DFS solution:
public class Solution {
    public boolean validTree(int n, int[][] edges) {
        
        // Create an adj list 
        List<List<Integer>> adjList = new ArrayList<List<Integer>>();
        for (int i = 0; i < n; i++) {
            adjList.add(new ArrayList<Integer>());
        }
        
        for (int[] edge : edges) {
            adjList.get(edge[1]).add(edge[0]);
            adjList.get(edge[0]).add(edge[1]);
        }
        
        boolean[] visited = new boolean[n];
        
        if (!validTreeHelper(n, edges, 0, -1, visited, adjList)) {
            return false;
        }
        
        // Check the islands
        for (boolean v : visited) {
            if (!v) {
                return false;
            }
        }
        
        return true;
    }
    
    private boolean validTreeHelper(int n, int[][] edges, int vertexId, int parentId, 
                                    boolean[] visited, List<List<Integer>> adjList) {
        if (visited[vertexId]) {
            return false;
        }
        
        visited[vertexId] = true;
        
        List<Integer> neighbors = adjList.get(vertexId);
        for (Integer neighbor : neighbors) {
            if (neighbor != parentId && !validTreeHelper(n, edges, neighbor, vertexId, visited, adjList)) {
                return false;
            }
        }
        
        return true;
    }
}

A BFS solution:
public class Solution {
    public boolean validTree(int n, int[][] edges) {
        
        // Create an adj list 
        List<List<Integer>> adjList = new ArrayList<List<Integer>>();
        for (int i = 0; i < n; i++) {
            adjList.add(new ArrayList<Integer>());
        }
        
        for (int[] edge : edges) {
            adjList.get(edge[1]).add(edge[0]);
            adjList.get(edge[0]).add(edge[1]);
        }
        
        boolean[] visited = new boolean[n];
        
        Queue<Integer> queue = new LinkedList<Integer>();
        queue.offer(0);
        
        while (!queue.isEmpty()) {
            int vertexId = queue.poll();
            
            if (visited[vertexId]) {
                return false;
            }
            
            visited[vertexId] = true;
            
            for (int neighbor : adjList.get(vertexId)) {
                if (!visited[neighbor]) {
                    queue.offer(neighbor);
                }
            }
        }
        
        // Check the islands
        for (boolean v : visited) {
            if (!v) {
                return false;
            }
        }
        
        return true;
    }
}

If a graph is valid binary tree, it must follow the two conditions:
1. num of edges = num of nodes - 1
2. There is only 1 CC

BFS Solution:
public class Solution {
    /**
     * @param n: An integer
     * @param edges: a list of undirected edges
     * @return: true if it's a valid tree, or false
     */
    public boolean validTree(int n, int[][] edges) {
        // write your code here
        if (n == 0) {
            return edges == null || edges.length == 0;
        }
        
        if (edges.length != n - 1) {
            return false;
        }
        
        Set<Integer> visited = new HashSet<>();
        
        List<List<Integer>> adjList = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            adjList.add(new ArrayList<>());
        }
        
        // add nodes to the adjList
        for (int[] edge : edges) {
            int from = edge[0];
            int to = edge[1];
            
            adjList.get(from).add(to);
            adjList.get(to).add(from);
        }
        
        // start bfs from each node, if it's not visited
        bfs(adjList, 0, visited);
        
        return visited.size() == n;
    }
    
    private void bfs(List<List<Integer>> adjList, int root, Set<Integer> visited) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(root);
        visited.add(root);
        
        while (!queue.isEmpty()) {
            int node = queue.poll();
            for (int neighbor : adjList.get(node)) {
                if (visited.contains(neighbor)) {
                    continue;
                }
                
                queue.offer(neighbor);
                visited.add(neighbor);
            }
        }
    }
}
Update on 1/11/2021: Union-Find

public class Solution {
    /**
     * @param n: An integer
     * @param edges: a list of undirected edges
     * @return: true if it's a valid tree, or false
     */
    public boolean validTree(int n, int[][] edges) {
        // write your code here
        if (n == 0) {
            return edges == null || edges.length == 0;
        }
        
        if (edges.length != n -1) {
            return false;
        }
        
        // get number of cc 
        UF uf = new UF(n);
        
        for (int[] edge : edges) {
            uf.union(edge[0], edge[1]);
        }
        
        return uf.getNumCC() == 1;
    }
}

class UF {
    private int n;
    private int[] parents;
    private int numCC;
    
    public UF(int n) {
        this.n = n;
        parents = new int[n];
        numCC = n;
        
        for (int i = 0; i < n; i++) {
            parents[i] = i;
        }
    }
    
    public int find(int x) {
        int root = x;
        while (parents[root] != root) {
            root = parents[root];
        }
        
        // path compression
        while (x != root) {
            int temp = parents[x];
            parents[x] = root;
            x = temp;
        }
        
        return root;
    }
    
    public void union(int x, int y) {
        int px = find(x);
        int py = find(y);
        
        if (px != py) {
            parents[px] = py;
            numCC--;
        }
    }
    
    public int getNumCC() {
        return numCC;
    }
}

Leetcode: Kth Smallest Element in a BST

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note: 
You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
Hint:
  1. Try to utilize the property of a BST.
  2. What if you could modify the BST node's structure?
  3. The optimal runtime complexity is O(height of BST).
A similar post can be found at : http://buttercola.blogspot.com/2014/10/facebook-print-n-th-node-in-binary-tree.html

Code (Java):
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    private int counter = 0;
    private boolean found = false;
    private int val = Integer.MIN_VALUE;
    public int kthSmallest(TreeNode root, int k) {
        if (root == null) {
            return 0;
        }
        
        kthSmallestHelper(root, k);
        
        return val;
    }
    
    private void kthSmallestHelper(TreeNode root, int k) {
        if (root == null) {
            return;
        }
        
        if (!found) {
            kthSmallestHelper(root.left, k);
        }
        
        counter++;
        if (counter == k) {
            found = true;
            val = root.val;
        }
        
        if (!found) {
            kthSmallestHelper(root.right, k);
        }
    }
}

An O(h) solution:
If the BST node's structure can be modified. We let each node maintain the number of nodes of its left subtree. Therefore, for each node, we can compare k with the number of its subtree. 

Code (Java):
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int kthSmallest(TreeNode root, int k) {
        if (root == null) {
            return 0;
        }
        
        int leftNodes = getNumberNodes(root.left);
        if(k == leftNodes + 1) {
            return root.val;
        } else if (k > leftNodes + 1) {
            return kthSmallest(root.right, k - leftNodes - 1);
        } else {
            return kthSmallest(root.left, k);
        }
    }
    
    private int getNumberNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        return getNumberNodes(root.left) + getNumberNodes(root.right) + 1;
    }
}
Update on 4/29/19:
/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */

public class Solution {
    /**
     * @param root: the given BST
     * @param k: the given k
     * @return: the kth smallest element in BST
     */
    public int kthSmallest(TreeNode root, int k) {
        // write your code here
        BSTNode bstRoot = buildBST(root);

        BSTNode p = bstRoot;

        while (p != null) {
            int numLeft = p.left == null ? 0 : p.left.numNodes;
            int numRight = p.right == null ? 0 : p.right.numNodes;

            if (k == numLeft + 1) {
                return p.val;
            }

            if (k <= numLeft) {
                p = p.left;
            } else {
                p = p.right;
                k = k- numLeft - 1;
            }
        }
        
        return -1;
    }

    private BSTNode buildBST(TreeNode root) {
        if (root == null) {
            return null;
        }

        BSTNode left = buildBST(root.left);
        BSTNode right = buildBST(root.right);

        int numNodes = (left == null ? 0 : left.numNodes) + 
                       (right == null ? 0 : right.numNodes) + 
                       1;

        BSTNode bstRoot = new BSTNode(root.val, numNodes);

        bstRoot.left = left;
        bstRoot.right = right;

        return bstRoot;
    }
}

class BSTNode {
    int val;
    int numNodes;
    BSTNode left, right;

    public BSTNode(int val, int numNodes) {
        this.val = val;
        this.numNodes = numNodes;
        left = right = null;
    }
}

Wednesday, August 19, 2015

Leetcode: Meeting Rooms

Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), determine if a person could attend all meetings.
For example,
Given [[0, 30],[5, 10],[15, 20]],
return false.
Understand the problem:
The problem looks very similar to the merge interval and insert intervals. So the idea is still the same: first sort the intervals according to the start times, then check if there is any overlap. 

Code (Java):
/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
public class Solution {
    public boolean canAttendMeetings(Interval[] intervals) {
        if (intervals == null || intervals.length ==0) {
            return true;
        }
        
        // Sort according to the start time
        Arrays.sort(intervals, new IntervalComparator());
        
        Interval prev = intervals[0];
        for (int i = 1; i < intervals.length; i++) {
            Interval curr = intervals[i];
            if (isOverlapped(prev, curr)) {
                return false;
            }
            prev = curr;
        }
        
        return true;
    }
    
    public class IntervalComparator implements Comparator<Interval> {
        @Override
        public int compare(Interval a, Interval b) {
            return a.start - b.start;
        }
    }
    
    private boolean isOverlapped(Interval a, Interval b) {
        return a.end > b.start;
    }
}

Leetcode: Missing Ranges

Given a sorted integer array where the range of elements are [lowerupper] inclusive, return its missing ranges.
For example, given [0, 1, 3, 50, 75]lower = 0 and upper = 99, return ["2", "4->49", "51->74", "76->99"].
Understand the problem:
The problem itself is not hard at all. The key is to handle several corner cases. e.g. 
 -- If the array is empty, the missing ranges should be from lower to upper, inclusive. 
 -- For the leading missing range, e.g. -2 , [-1], -1. The output should be "-2". Note that the lower bound is inclusive. 
 -- For the trailing missing range, e.g. -2, [-2], 1, the output should be "-1->1". The upper bound is inclusive as well. 

Code (Java):
public class Solution {
    public List<String> findMissingRanges(int[] nums, int lower, int upper) {
        List<String> result = new ArrayList<String>();
        if (nums == null || nums.length == 0) {
            outputToResult(lower, upper, result);
            return result;
        }
        
        // leading missing range
        if (nums[0] - lower > 0) {
            outputToResult(lower, nums[0] - 1, result);
        }
        
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] - nums[i - 1] > 1) {
                outputToResult(nums[i - 1] + 1, nums[i] - 1, result);
            }
        }
        
        // trailing missage ranges
        if (upper - nums[nums.length - 1] > 0) {
            outputToResult(nums[nums.length - 1] + 1, upper, result);
        }
        
        return result;
    }
    
    private void outputToResult(int start, int end, List<String> result) {
        StringBuffer sb = new StringBuffer();
        if (start == end) {
            sb.append(start);
        } else {
            sb.append(start + "->" + end);
        }
        
        result.add(sb.toString());
    }
}

Leetcode: The Skyline Problem

A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed by these buildings collectively (Figure B).
Buildings Skyline Contour
The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi], where Li and Ri are the x coordinates of the left and right edge of the ith building, respectively, and Hi is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] .
The output is a list of "key points" (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], ... ] that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.
For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ].
Notes:


  • The number of buildings in any input list is guaranteed to be in the range [0, 10000].
  • The input list is already sorted in ascending order by the left x position Li.
  • The output list must be sorted by the x position.
  • There must be no consecutive horizontal lines of equal height in the output skyline. For instance, [...[2 3], [4 5], [7 5], [11 5], [12 7]...] is not acceptable; the three lines of height 5 should be merged into one in the final output as such: [...[2 3], [4 5], [12 7], ...]
Understand the problem:
The problem looks quite tricky. It looks very like the segment intervals problem. For this kind of problems, one general solution is :
  -- First, split the left key point and the right key point into two parts and store into another data structure. For this problem, [2 9 10] can be split into [2, 10, L] and [9, 10, R]
  -- Then, sort the split list according to the x coordinate, if equal, sort by height. Note that for this problem, if two x coordinates are Left end, the greater height should be before the lower, because the lower height is hidden. If both are Right end, put the lower first. 
  -- Thirdly, iterate the sorted list. If the end point is left. Put into the priority queue. Note that if the priority queue is empty or the height of the end point is greater than the peek of the pq, put the end point into result list. If the end point is right. Remove the point from pq. If pq is empty then, put a <x, 0> into result list. Else, if the height of the end point is greater than the peek of the pq, put <x, peek()> into the result list. 

Code (Java):
public class Solution {
    private class Edge {
        private int x;
        private int height;
        private boolean isLeft;
        
        // Constructor
        public Edge(int x, int height, boolean isLeft) {
            this.x = x;
            this.height = height;
            this.isLeft = isLeft;
        }
    }
    
    public List<int[]> getSkyline(int[][] buildings) {
        List<int[]> result = new ArrayList<int[]>();
        
        if (buildings == null || buildings.length == 0 || buildings[0].length == 0) {
            return result;
        }
        
        PriorityQueue<Integer> pq = new PriorityQueue<>(1000, Collections.reverseOrder());
        
        // Parse buildings and fill the edges
        List<Edge> edges = new ArrayList<Edge>();
        for (int[] building : buildings) {
            Edge leftEdge = new Edge(building[0], building[2], true);
            edges.add(leftEdge);
            
            Edge rightEdge = new Edge(building[1], building[2], false);
            edges.add(rightEdge);
        }
        
        // Sort the edges according to the left keypoint
        Collections.sort(edges, new EdgeComparator());
        
        // Iterate all sorted edges
        for (Edge edge : edges) {
            if (edge.isLeft) {
                if (pq.isEmpty() || edge.height > pq.peek()) {
                    result.add(new int[]{edge.x, edge.height});
                }
                pq.offer(edge.height);
            } else {
                pq.remove(edge.height);
                if (pq.isEmpty()) {
                    result.add(new int[]{edge.x, 0});
                } else if (edge.height > pq.peek()) {
                    result.add(new int[]{edge.x, pq.peek()});
                }
            }
        }
        
        return result;
    }
    
    public class EdgeComparator implements Comparator<Edge> {
        @Override
        public int compare(Edge a, Edge b) {
            if (a.x != b.x) {
                return a.x - b.x;
            }
            
            if (a.isLeft && b.isLeft) {
                return b.height - a.height;
            }
            
            if (!a.isLeft && !b.isLeft) {
                return a.height - b.height;
            }
            
            return a.isLeft ? -1 : 1;
        }
    }
}

Analysis:
Now let's analyze the time and the space complexity of the solution. Sorting the 2 * N list takes O(nlogn) time. For each of the 2 * n edges, peek() the max takes O(1) time but add and remove takes O(log n) time. So the overall time complexity is O(n * logn). 

An alternative solution:
Notice that "key points" are either the left or right edges of the buildings. Therefore, we first obtain both the edges of all the N buildings, and store the 2N edges in a sorted array. Maintain a max-heap of building heights while scanning through the edge array: If the current edge is a left edge, then add the height of its associated building to the max-heap; if the edge is a right one, remove the associated height from the heap. Then we take the top value of the heap (yi) as the maximum height at the current edge position (xi). Now (xi, yi) is a potential key point. If yi is the same as the height of the last key point in the result list, it means that this key point is not a REAL key point, but rather a horizontal continuation of the last point, so it should be discarded; otherwise, we add (xi,yi) to the result list because it is a real key point. Repeat this process until all the edges are checked.
It takes O(NlogN) time to sort the edge array. For each of the 2N edges, it takes O(1) time to query the maximum height but O(logN) time to add or remove elements. Overall, this solution takes O(NlogN) time.
Code(Java):
public class Solution {
    private class Edge {
        private int x;
        private int height;
        private boolean isLeft;
        
        // Constructor
        public Edge(int x, int height, boolean isLeft) {
            this.x = x;
            this.height = height;
            this.isLeft = isLeft;
        }
    }
    
    public List<int[]> getSkyline(int[][] buildings) {
        List<int[]> result = new ArrayList<int[]>();
        
        if (buildings == null || buildings.length == 0 || buildings[0].length == 0) {
            return result;
        }
        
        PriorityQueue<Integer> pq = new PriorityQueue<>(1000, Collections.reverseOrder());
        
        // Parse buildings and fill the edges
        List<Edge> edges = new ArrayList<Edge>();
        for (int[] building : buildings) {
            Edge leftEdge = new Edge(building[0], building[2], true);
            edges.add(leftEdge);
            
            Edge rightEdge = new Edge(building[1], building[2], false);
            edges.add(rightEdge);
        }
        
        // Sort the edges according to the left keypoint
        Collections.sort(edges, new EdgeComparator());
        
        pq.offer(0);
        int prev = 0;
        
        // Iterate all sorted edges
        for (Edge edge : edges) {
            if (edge.isLeft) {
                pq.offer(edge.height);
            } else {
                pq.remove(edge.height);
            }
            
            int curr = pq.peek();
            
            if (curr != prev) {
                result.add(new int[]{edge.x, curr});
                prev = curr;
            }
        }
        
        return result;
    }
    
    public class EdgeComparator implements Comparator<Edge> {
        @Override
        public int compare(Edge a, Edge b) {
            if (a.x != b.x) {
                return a.x - b.x;
            }
            
            if (a.isLeft && b.isLeft) {
                return b.height - a.height;
            }
            
            if (!a.isLeft && !b.isLeft) {
                return a.height - b.height;
            }
            
            return a.isLeft ? -1 : 1;
        }
    }
}

Update on 3/27:
public class Solution {
    /**
     * @param buildings: A list of lists of integers
     * @return: Find the outline of those buildings
     */
    public List<List<Integer>> buildingOutline(int[][] buildings) {
        if (buildings == null || buildings.length == 0) {
            return new ArrayList<>();
        }

        List<Event> events = new ArrayList<>();
        for (int[] building : buildings) {
            events.add(new Event(building[0], building[2], 0));
            events.add(new Event(building[1], building[2], 1));
        }

        Collections.sort(events, new MyEventComparator());

        PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder()); // pq store the heights
        Map<Integer, Integer> map = new HashMap<>(); // <height, refCount>
        List<List<Integer>> ans = new ArrayList<>();

        for (Event event : events) {
            if (event.flag == 0) {
                if (pq.isEmpty() || event.y > pq.peek()) {
                    List<Integer> list = new ArrayList<>();
                    list.add(event.x);
                    list.add(event.y);
                    ans.add(list);
                }

                if (map.containsKey(event.y)) {
                    int count = map.get(event.y);
                    count++;
                    map.put(event.y, count);
                } else {
                    map.put(event.y, 1);
                    pq.offer(event.y);
                }
            } else {
                int count = map.get(event.y);
                if (count == 1) {
                    pq.remove(event.y);
                    map.remove(event.y);
                } else {
                    map.put(event.y, count - 1);
                }
                if (pq.isEmpty()) {
                    List<Integer> list = new ArrayList<>();
                    list.add(event.x);
                    list.add(0);
                    ans.add(list);
                } else if (event.y > pq.peek()) {
                    List<Integer> list = new ArrayList<>();
                    list.add(event.x);
                    list.add(pq.peek());
                    ans.add(list);
                }
            }
        }
        
        List<List<Integer>> ans2 = new ArrayList<>();
        for (int i = 0; i < ans.size() - 1; i++) {
            if (ans.get(i).get(1) > 0) {
                List<Integer> list = new ArrayList<>();
                list.add(ans.get(i).get(0));
                list.add(ans.get(i + 1).get(0));
                list.add(ans.get(i).get(1));
                
                ans2.add(list);
            }
        }
        
        return ans2;
    }
}

class Event {
    int x;
    int y;
    int flag; // 0 start 1 end

    public Event(int x, int y, int flag) {
        this.x = x;
        this.y = y;
        this.flag = flag;
    }
}

class MyEventComparator implements Comparator<Event> {
    @Override
    public int compare(Event a, Event b) {
        if (a.x != b.x) {
            return a.x - b.x;
        }
        

        if (a.flag == 0 && b.flag == 0) {
            return b.y - a.y;
        }

        if (a.flag == 1 && b.flag == 1) {
            return a.y - b.y;
        }

        return a.flag == 0 ? -1 : 1;
    }
}

Some corner cases to consider:
1. In the compare function, what if x is the same? Then we need to determine which one first.
2. What if we insert cities with the same heights? We need a ref count to maintain the current max height

Tuesday, August 18, 2015

Leetcode: Number of Islands

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
Understand the problem:
This problem is an alternative view of connected components in a undirected graph. It could be easily solved by using either DFS or BFS. 

DFS Solution (Java):
public class Solution {
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int rows = grid.length;
        int cols = grid[0].length;
        
        boolean[][] visited = new boolean[rows][cols];
        int result = 0;
        
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (grid[i][j] == '1' && !visited[i][j]) {
                    result++;
                    numIslandsHelper(grid, visited, i, j, rows, cols);
                }
            }
        }
        
        return result;
    }
    
    private void numIslandsHelper(char[][] grid, boolean[][] visited, int i, int j, int numRows, int numCols) {
        if (i < 0 || i >= numRows) {
            return;
        }
        
        if (j < 0 || j >= numCols) {
            return;
        }
        
        if (visited[i][j]) {
            return;
        }
        
        // If water
        if (grid[i][j] == '0') {
            return;
        }
        
        // Mark the visted[i][j] = true
        visited[i][j] = true;
        
        // Go up, down, left and right
        numIslandsHelper(grid, visited, i - 1, j, numRows, numCols);
        numIslandsHelper(grid, visited, i + 1, j, numRows, numCols);
        numIslandsHelper(grid, visited, i, j - 1, numRows, numCols);
        numIslandsHelper(grid, visited, i, j + 1, numRows, numCols);
    }
}

A BFS Solution:
public class Solution {
    private Queue<Integer> queue = new LinkedList();
    
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int rows = grid.length;
        int cols = grid[0].length;
        boolean[][] visited = new boolean[rows][cols];
        
        int result = 0;
        
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (grid[i][j] == '1' && !visited[i][j]) {
                    result++;
                    numIslandsHelper(grid, visited, i, j, rows, cols);
                }
            }
        }
        return result;
    }
    
    private void numIslandsHelper(char[][] grid, boolean[][] visited, int i, int j, int numRows, int numCols) {
        fill(grid, visited, i, j, numRows, numCols);
        
        while (!queue.isEmpty()) {      
            int cord = queue.poll();
            int x = cord / numCols;
            int y = cord % numCols;
    
            fill(grid, visited, x - 1, y, numRows, numCols);
            fill(grid, visited, x + 1, y, numRows, numCols);
            fill(grid, visited, x, y - 1, numRows, numCols);
            fill(grid, visited, x, y + 1, numRows, numCols);
        }
    }
    
    private void fill(char[][] grid, boolean[][] visited, int i, int j, int numRows, int numCols) {
        if (i < 0 || i >= numRows || j < 0 || j >= numCols) {
            return;
        }
        
        if (visited[i][j] || grid[i][j] == '0') {
            return;
        }
        
        visited[i][j] = true;
        
        queue.offer(i * numCols + j);
    }
}

Update on 1/25/16:
Union-find Solution:
public class Solution {
    private int[][] dir = new int[][]{{-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[] parents = new int[m * n];
        int count = 0;
        
        // Step 1: initialize each node, for each's parent is itself
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int id = i * n + j;
                parents[id] = id;
            }
        }
        
        // step 2: iterate each node, and connect the neighbors
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '0') {
                    continue;
                }
                
                for (int[] row : dir) {
                    int x = i + row[0];
                    int y = j + row[1];
                    if (isValid(grid, x, y)) {
                        int p = i * n + j;
                        int q = x * n + y;
                        connect(parents, p, q);
                    }
                }
            }
        }
        
        // step 3: count the number of cc
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int id = i * n + j;
                if (grid[i][j] == '1' && parents[id] == id) {
                    count++;
                }
            }
        }
        
        return count;
    }
    
    private boolean isValid(char[][] grid, int x, int y) {
        int m = grid.length;
        int n = grid[0].length;
        
        return x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1';
    }
    
    private void connect(int[] parents, int p, int q) {
        int pRoot = find(parents, p);
        int qRoot = find(parents, q);
        
        if (pRoot == qRoot) {
            return;
        }
        
        parents[pRoot] = qRoot;
    }
    
    private int find(int[] parents, int id) {
        while (parents[id] != id) {
            id = parents[id];
        }
        
        return id;
    }
}

Updata on 4/21/19:
public class Solution {
    /**
     * @param grid: a boolean 2D matrix
     * @return: an integer
     */
    public int numIslands(boolean[][] grid) {
        // write your code here
        if (grid == null || grid.length == 0) {
            return 0;
        }
        
        int nRows = grid.length;
        int nCols = grid[0].length;
        
        int[] parents = new int[nRows * nCols];
        for (int i = 0; i < parents.length; i++) {
            parents[i] = i;
        }
        
        for (int i = 0; i < nRows; i++) {
            for (int j = 0; j < nCols; j++) {
                if (grid[i][j]) {
                    union(grid, i, j, parents);
                }
            }
        }
        
        int numIslands = 0;
        
        for (int i = 0; i < parents.length; i++) {
            int nx = i / nCols;
            int ny = i % nCols;
            
            if (grid[nx][ny] && parents[i] == i) {
                numIslands++;
            }
        }
        
        return numIslands;
    }
    
    private void union(boolean[][] grid, int x, int y, int[] parents) {
        int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        
        int nRows = grid.length;
        int nCols = grid[0].length;
        
        for (int i = 0; i < 4; i++) {
            int nx = x + dirs[i][0];
            int ny = y + dirs[i][1];
            
            if (nx >= 0 && nx < nRows && ny >= 0 && ny < nCols && grid[nx][ny]) {
                int myParrent = find(parents, x * nCols + y);
                int neighborParrent = find(parents, nx * nCols + ny);
                
                if (myParrent != neighborParrent) {
                    parents[myParrent] = neighborParrent;
                }
            }
        }
    }
    
    private int find(int[] parents, int x) {
        int root = x;
        while (parents[root] != root) {
            root = parents[root];
        }
        
        // path compression
        //
        while (x != root) {
            int temp = parents[x];
            parents[x] = root;
            x = temp;
        }
        
        return root;
    }
}

Leetcode: Ugly Number

Write a program to check whether a given number is an ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7.
Note that 1 is typically treated as an ugly number.
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.
Understand the problem:
This problem can be solved by using greedy algorithm. First check if it could be divided by 2s, if not then 3s, and then 5s. Finally check if the number is 1. If yes, return true else return false. 

Code (Java):
public class Solution {
    public boolean isUgly(int num) {
        if (num <= 0) {
            return false;
        }
        
        while (num > 1 && num % 2 == 0) {
            num /= 2;
        }
        
        while (num > 1 && num % 3 == 0) {
            num /= 3;
        }
        
        while (num > 1 && num % 5 == 0) {
            num /= 5;
        }
        
        if (num == 1) {
            return true;
        } else {
            return false;
        }
    }
}