Friday, September 4, 2015

Leetcode: Sliding Window Maximum

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.
For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7
Therefore, return the max sliding window as [3,3,5,5,6,7].
Note: 
You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.
Follow up:
Could you solve it in linear time?
Hint:
  1. How about using a data structure such as deque (double-ended queue)?
  2. The queue size need not be the same as the window’s size.
  3. Remove redundant elements and the queue should store only elements that need to be considered.
Understand the problem:
If the problem is solved by using a heap, the complexity would be n logk. 
Since the problem asks for liner time solution, we can use a deque. 

We enqueue the element from the end of the deque, if the end of the deque is less than the current element, delete the current element. Then we enqueue the element into the end of the deque. If the size of the deque is greater than the k, we remove element from the front. 

Code (Java):
public class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k <= 0) {
            return new int[0];
        }
        
        Deque<Integer> deque = new LinkedList<Integer>();
        int[] result = new int[nums.length - k + 1];
        
        for (int i = 0; i < nums.length; i++) {
            while (!deque.isEmpty() && nums[i] >= nums[deque.getLast()]) {
                deque.removeLast();
            }
            
            deque.addLast(i);
            
            // Remove if the size of the deque is greater than k
            if (i - deque.getFirst() + 1 > k) {
                deque.removeFirst();
            }
            
            // Add into the result
            if (i + 1 >= k) {
                result[i + 1 - k] = nums[deque.getFirst()];
            }
        }
        
        return result;
    }
}

Summary:
Note that for a deque, first is the left end and Last is the right end. 
The numbers in the deque is actually in reversed sorted order (large first) from front to end.
[ 1 largest, 2nd largest, 3rd largest ...                                 ]
front                                                                                     end

Update on 2/2/2021:

public class Solution {
    /**
     * @param nums: A list of integers.
     * @param k: An integer
     * @return: The maximum number inside the window at each moving.
     */
    public List<Integer> maxSlidingWindow(int[] nums, int k) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        
        if (nums == null || nums.length == 0 || k > nums.length) {
            return ans; 
        }
        
        // deque is a mono-deceasing queue
        // |               |
        // first           last
        // hi              lo
        Deque<Integer> deque = new LinkedList<>();
        
        for (int i = 0; i < nums.length; i++) {
            while (!deque.isEmpty() && nums[i] > nums[deque.peekLast()]) {
                deque.pollLast();
            }
            
            // add the nums[i] into the last
            deque.offerLast(i);
            
            if (i + 1 - k >= 0) {
                // poll from the first
                if (i - deque.peekFirst() + 1 > k) {
                    deque.pollFirst();
                }
                
                ans.add(nums[deque.peekFirst()]);
            }
        }
        
        return ans;
    }
}

Leetcode: Different Ways to Add Parentheses

Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +,- and *.

Example 1
Input: "2-1-1".
((2-1)-1) = 0
(2-(1-1)) = 2
Output: [0, 2]

Example 2
Input: "2*3-4*5"
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
Output: [-34, -14, -10, -10, 10]
Understand the problem:
The question can be solved by using divide-and-conquer. We first cut the expression into two halves and calculate the list of result for each half. Then we traverse the two lists and get the final result. 

Code (Java):
public class Solution {
    public List<Integer> diffWaysToCompute(String input) {
        List<Integer> result = new ArrayList<>();
        if (input == null || input.length() == 0) {
            return result;
        }
        
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            
            if (!isOperator(c)) {
                continue;
            }
            
            List<Integer> left = diffWaysToCompute(input.substring(0, i));
            List<Integer> right = diffWaysToCompute(input.substring(i + 1));
            
            for (int num1 : left) {
                for (int num2 : right) {
                    int val = calculate(num1, num2, c);
                    result.add(val);
                }
            }
        }
        
        // only contains one number
        if (result.isEmpty()) {
            result.add(Integer.parseInt(input));
        }
        
        return result;
    }
    
    private int calculate(int num1, int num2, char operator) {
        int result = 0;
        
        switch(operator) {
            case '+' : result = num1 + num2;
            break;
            
            case '-' : result = num1 - num2;
            break;
            
            case '*' : result = num1 * num2;
            break;
        }
        
        return result;
    }
    
    private boolean isOperator(char operator) {
        return (operator == '+') || (operator == '-') || (operator == '*');
    }
}

Summary:
The problem itself is not hard. The essence of the problem is to compute the different ways to compute the expression. There is only one trick here is how to handle the input has only one number there, e.g. "1". Then we need to add the number into the result list. The idea is to check if the result is empty after the divide-and-conquer step. If it is empty, means only one number left in the input. Note that we cannot check using if the first character of the input string is digit, because each and every input string starts from a number. 

Leetcode: Shortest Palindrome

Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
For example:
Given "aacecaaa", return "aaacecaaa".
Given "abcd", return "dcbabcd".
Understand the problem:
The straight-forward solution is: find the longest palindrome substring starting with s[0]. Then insert the remaining of the string s to the front in a reverse order.

Code (Java):
public class Solution {
    public String shortestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        
        int maxLen = 0;
        // Step 1: find the longest palindromic substring including s.charAt(0)
        for (int i = 0; i < s.length(); i++) {
            // Odd
            int p = i - 1;
            int q = i + 1;
            int len = 1;
            while (p >= 0 && q < s.length() && s.charAt(p) == s.charAt(q)) {
                len += 2;
                p--;
                q++;
            }
            
            if (p == -1 && len > maxLen) {
                maxLen = len;
            }
            
            // Even
            p = i;
            q = i + 1;
            len = 0;
            while (p >= 0 && q < s.length() && s.charAt(p) == s.charAt(q)) {
                p--;
                q++;
                len += 2;
            }
            
            if (p == -1 && len > maxLen) {
                maxLen = len;
            }
        }
        
        int j = maxLen;
        StringBuffer sb = new StringBuffer();
        for (int m = s.length() - 1; m >= j; m--) {
            sb.append(s.charAt(m));
        }
        
        sb.append(s);
        
        return sb.toString();
    }
}

Analysis:
The time complexity to find out the longest palindrome substring starting from s[0] is O(n^2). So the overall time complexity is O(n^2) as well. 

KMP solution:

Leetcode: Maximal Square

Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and return its area.
For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.
Understand the problem:
This question can be solved by using DP. 
  -- Define dp[i][j] as the length of the maximal square of which the right bottom point ended with matrix[i][j]. 
  -- Initial value dp[0][j] = matrix[0][j]; dp[i][0] = matrix[i][0];
  -- Transit function: If matrix[i][j] == 1, dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
  -- Final state, max(dp[i][j] * dp[i][j])


Code (Java):
public class Solution {
    public int maximalSquare(char[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        
        int rows = matrix.length;
        int cols = matrix[0].length;
        
        int[][] dp = new int[rows][cols];
        
        // Initialization
        for (int i = 0; i < cols; i++) {
            dp[0][i] = matrix[0][i] - '0';
        }
        
        for (int i = 0; i < rows; i++) {
            dp[i][0] = matrix[i][0] - '0';
        }
        
        for (int i = 1; i < rows; i++) {
            for (int j = 1; j < cols; j++) {
                if (matrix[i][j] == '1') {
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j], 
                               dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
                }
            }
        }
        
        int maxArea = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                maxArea = Math.max(maxArea, dp[i][j] * dp[i][j]);
            }
        }
        
        return maxArea;
    }
}

Update on 4/2/19: Rolling array
public class Solution {
    /**
     * @param matrix: a matrix of 0 and 1
     * @return: an integer
     */
    public int maxSquare(int[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        
        int m = matrix.length;
        int n = matrix[0].length;
        
        int maxLen = 0;
        
        int[][] dp = new int[2][n];
        for (int i = 0; i < n; i++) {
            if (matrix[0][i] == 1) {
                dp[0][i] = 1;
                maxLen = Math.max(maxLen, dp[0][i]);
            }
        }
        
        int cur = 0;
        int old = 0;
        
        for (int i = 1; i < m; i++) {
            old = cur;
            cur = 1 - cur;
            dp[cur][0] = matrix[i][0] == 1 ? 1 : 0;
            maxLen = Math.max(maxLen, dp[cur][0]);
            
            for (int j = 1; j < n; j++) {
                if (matrix[i][j] == 1) {
                    dp[cur][j] = Math.min(dp[old][j - 1], Math.min(dp[old][j], dp[cur][j - 1])) + 1;
                } else {
                    dp[cur][j] = 0;
                }
                
                maxLen = Math.max(maxLen, dp[cur][j]);
            }
        }
        
        return maxLen * maxLen;
        
    }
}

Wednesday, September 2, 2015

Leetcode: Word search II

Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
For example,
Given words = ["oath","pea","eat","rain"] and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]
Return ["eat","oath"].
Note:
You may assume that all inputs are consist of lowercase letters a-z.
You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?
If the current candidate does not exist in all words' prefix, you could stop backtracking immediately. What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not? How about a Trie? If you would like to learn how to implement a basic trie, please work on this problem: Implement Trie (Prefix Tree) first.
A time limit exceed solution:
Use a trie to save the word which does not in the board. So each time for a new word, we first search if the prefix exist in the trie. If yes, no need to search the board again. 
Simply put, the trie stores the prefix which does not exist in the board, so we don't need to waste of time to search again and again. 

Code (Java):
public class Solution {
    private int rows;
    private int cols;
    public List<String> findWords(char[][] board, String[] words) {
        List<String> result = new ArrayList<String>();
        if (board == null || board.length == 0 || words == null || words.length == 0) {
            return result;
        } 
        
        Set<String> set = new HashSet<String>();
        
        Trie trie = new Trie();
        
        this.rows = board.length;
        this.cols = board[0].length;
        
        for (String word : words) {
            if (trie.searchPrefix(word) == false) {
                if (searchBoard(board, word)) {
                    if (!set.contains(word)) {
                        set.add(word);
                    }
                } else {
                    trie.insert(word);
                }
            } else {
                trie.insert(word);
            }
        }
        
        return new ArrayList<String>(set);
    }
    
    private boolean searchBoard(char[][] board, String word) {
        boolean[][] visited = new boolean[rows][cols];
        
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (searchBoardHelper(board, i, j, word, 0, visited)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    private boolean searchBoardHelper(char[][] board, int row, int col, String word, int index, boolean[][] visited) {
        if (row < 0 || row >= rows || col < 0 || col >= cols) {
            return false;
        }
        
        if (visited[row][col]) {
            return false;
        }
        
        if (board[row][col] != word.charAt(index)) {
            return false;
        }
        
        visited[row][col] = true;
        
        if (index == word.length() - 1 && board[row][col] == word.charAt(index)) {
            return true;
        }
        
        boolean ret; 
        ret = searchBoardHelper(board, row - 1, col, word, index + 1, visited) ||
              searchBoardHelper(board, row + 1, col, word, index + 1, visited) ||
              searchBoardHelper(board, row, col - 1, word, index + 1, visited) ||
              searchBoardHelper(board, row, col + 1, word, index + 1, visited);
        
        visited[row][col] = false;
        
        return ret;
    }
    
    class Trie {
        private TrieNode root = new TrieNode();
        
        // Insert a word
        void insert(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    curr.children[character - offset] = 
                        new TrieNode(character, i == s.length() - 1 ? true : false);
                } else {
                    if (i == s.length() - 1) {
                        curr.children[character - offset].leaf = true;
                    }
                }
                curr = curr.children[character - offset];
            }
        }
        
        // Search for prefix
        boolean searchPrefix(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    return false;
                } else if (curr.children[character - offset] != null && curr.children[character - offset].leaf) {
                    return true;
                }
                
                curr = curr.children[character - offset];
            }
            
            return false;
        }
    }
    
    class TrieNode {
        char val;
        boolean leaf;
        TrieNode[] children;
        
        public TrieNode() {
            this.val = '\0';
            this.children = new TrieNode[26];
        } 
        
        public TrieNode(char val, boolean leaf) {
            this.val = val;
            this.leaf = leaf;
            this.children = new TrieNode[26];
        }
    }
}

Code (Java):
public class Solution {
    private int rows;
    private int cols;
    public List<String> findWords(char[][] board, String[] words) {
        List<String> result = new ArrayList<String>();
        if (board == null || board.length == 0 || words == null || words.length == 0) {
            return result;
        } 
        
        Set<String> set = new HashSet<String>();
        
        Trie trie = new Trie();
        
        this.rows = board.length;
        this.cols = board[0].length;
        
        // Step 1: insert all words into a trie
        for (String word : words) {
            trie.insert(word);
        }
        
        // Step 2: search the board
        boolean[][] visited = new boolean[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                searchBoardHelper(board, i, j, "", visited, trie, set);
            }
        }
        
        return new ArrayList<String>(set);
    }
    
    
    private void searchBoardHelper(char[][] board, int row, int col, String word, 
                                      boolean[][] visited, Trie trie, Set<String> set) {
        if (row < 0 || row >= rows || col < 0 || col >= cols) {
            return;
        }
        
        if (visited[row][col]) {
            return;
        }
        
        word += board[row][col];
        
        if (!trie.searchPrefix(word)) {
            return;
        }
        
        if (trie.search(word)) {
            set.add(word);
        }
        
        visited[row][col] = true;
        
        searchBoardHelper(board, row - 1, col, word, visited, trie, set);
        searchBoardHelper(board, row + 1, col, word, visited, trie, set);
        searchBoardHelper(board, row, col - 1, word, visited, trie, set);
        searchBoardHelper(board, row, col + 1, word, visited, trie, set);
        
        visited[row][col] = false;
    }
    
    class Trie {
        private TrieNode root = new TrieNode();
        
        // Insert a word
        void insert(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    curr.children[character - offset] = 
                        new TrieNode(character, i == s.length() - 1 ? true : false);
                } else {
                    if (i == s.length() - 1) {
                        curr.children[character - offset].leaf = true;
                    }
                }
                curr = curr.children[character - offset];
            }
        }
        
        
        // Search a word
        boolean search(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    return false;
                }
                curr = curr.children[character - offset];
            }
            
            if (curr != null && !curr.leaf) {
                return false;
            }
            
            return true;
        }
        
        // Search for prefix
        boolean searchPrefix(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    return false;
                } 
                
                curr = curr.children[character - offset];
            }
            
            return true;
        }
    }
    
    class TrieNode {
        char val;
        boolean leaf;
        TrieNode[] children;
        
        public TrieNode() {
            this.val = '\0';
            this.children = new TrieNode[26];
        } 
        
        public TrieNode(char val, boolean leaf) {
            this.val = val;
            this.leaf = leaf;
            this.children = new TrieNode[26];
        }
    }
}

Analysis:
Let's think about the naive solution first. The naive solution is we search the board for each board. So for the dict with n words, and assume the ave. length of each word has length of m. Then without using a Trie, the time complexity would be O(n * rows * cols  * 4^m). 

Now let's analyze the time complexity of using a Trie. We put each word into the trie. Search in the Trie takes O(m) time, so the time complexity would be O(rows * cols * m * 4^m). Since mostly m << n, using a trie would save lots of time. 

A better solution:
The key observation with the previous solution is we don't need to search the trie for each prefix from the root; Instead, we can keep track of the current pointer to the trie. The time complexity is  O(rows * cols * 4^m).

Code (Java):
public class Solution {
    /**
     * @param board: A list of lists of character
     * @param words: A list of string
     * @return: A list of string
     */
    public List<String> wordSearchII(char[][] board, List<String> words) {
        List<String> ans = new ArrayList<>();
        if (board == null || board[0] == null || words == null) {
            return ans;
        }

        Set<String> set = new HashSet<>();
        boolean[][] visited = new boolean[board.length][board[0].length];

        // step 1: create a trie and put words into the trie
        //
        Trie trie = new Trie();
        for (String word : words) {
            trie.insert(word);
        }

        // step 2: scan the board and check if the word in the trie
        //
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                wordSearchHelper(i, j, board, visited, set, trie.root);
            }
        }

        return new ArrayList<>(set);
    }

    private void wordSearchHelper(int row, int col, char[][] board, boolean[][] visited, Set<String> set, TrieNode p) {
        int m = board.length;
        int n = board[0].length;

        if (row < 0 || row >= m || col < 0 || col >= n || visited[row][col]) {
            return;
        }

        char c = board[row][col];

        if (p.children[c - 'a'] == null) {
            return;
        }

        visited[row][col] = true;
        p = p.children[c - 'a'];

        if (!p.word.isEmpty()) {
            set.add(p.word);
        }

        int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        for (int i = 0; i < 4; i++) {
            wordSearchHelper(row + dirs[i][0], col + dirs[i][1], board, visited, set, p);
        }

        visited[row][col] = false;
    }
}

class Trie {
    TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    public void insert(String word) {
        TrieNode p = root;
        for (char c : word.toCharArray()) {
            if (p.children[c - 'a'] == null) {
                p.children[c - 'a'] = new TrieNode();
            }

            p = p.children[c - 'a'];
        }

        p.word = word;
    }
}

class TrieNode {
    TrieNode[] children;
    String word;

    public TrieNode() {
        children = new TrieNode[26];
        word = "";
    }
}

Update on 1/23/2021:

public class Solution {
    /**
     * @param board: A list of lists of character
     * @param words: A list of string
     * @return: A list of string
     */
    public List<String> wordSearchII(char[][] board, List<String> words) {
        // write your code here
        List<String> res = new ArrayList<>();
        if (board == null || board.length == 0 || words == null || words.size() == 0) {
            return res;
        }
        
        Trie trie = new Trie();
        
        for (String word : words) {
            trie.addWord(word);
        }
        
        int nRows = board.length;
        int nCols = board[0].length;
        
        Set<String> set = new HashSet<>();
        
        for (int i = 0; i < nRows; i++) {
            for (int j = 0; j < nCols; j++) {
                TrieNode p = trie.root;
                boolean[][] visited = new boolean[nRows][nCols];
                if (p.children[board[i][j] - 'a'] != null) {
                    search(i, j, board, visited, p.children[board[i][j] - 'a'], set);
                }
            }
        }
        
        return new ArrayList<>(set);
    }
    
    private void search(int row, int col, char[][] board, boolean[][] visited, TrieNode p, Set<String> res) {
        //char c = board[row][col];
        
        if (p == null) {
            return;
        }
        
        if (p.word != null) {
            res.add(p.word);
        }
        
        int[][] dirs = {{-1 ,0}, {1, 0}, {0, -1}, {0, 1}};
        int nRows = board.length;
        int nCols = board[0].length;
        
        visited[row][col] = true;
        for (int[] dir : dirs) {
            int nextRow = row + dir[0];
            int nextCol = col + dir[1];
            
            if (nextRow >= 0 && nextRow < nRows && nextCol >= 0 && nextCol < nCols && !visited[nextRow][nextCol]) {
                search(nextRow, nextCol, board, visited, p.children[board[nextRow][nextCol] - 'a'], res);
            }
        }
        
        visited[row][col] = false;
    }
}

class TrieNode {
    TrieNode[] children;
    String word;
    
    public TrieNode() {
        this.children = new TrieNode[26];
        word = null;
    }
}

class Trie {
    public TrieNode root;
    
    public Trie() {
        this.root = new TrieNode();
    }
    
    public void addWord(String word) {
        TrieNode p = root;
        
        for (char c : word.toCharArray()) {
            if (p.children[c - 'a'] == null) {
                p.children[c - 'a'] = new TrieNode();
            }
            
            p = p.children[c - 'a'];
        }
        
        p.word = word;
    }
}

Leetcode: Basic Calculator II

Implement a basic calculator to evaluate a simple expression string.
The expression string contains only non-negative integers, +-*/ operators and empty spaces . The integer division should truncate toward zero.
You may assume that the given expression is always valid.
Some examples:
"3+2*2" = 7
" 3/2 " = 1
" 3+5 / 2 " = 5
Note: Do not use the eval built-in library function.
Code (Java):
public class Solution {
    public int calculate(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        
        String delim = "[ ]+";
        s = s.replaceAll(delim, "");
        
        Stack<Integer> numStack = new Stack<Integer>();
        Stack<Character> opStack = new Stack<Character>();
        
        int result = 0;
        
        int i = 0;
        while (i < s.length()) {
            char token = s.charAt(i);
            if (isNumber(token)) {
                StringBuffer sb = new StringBuffer();
                while (i < s.length() && isNumber(s.charAt(i))) {
                    sb.append(s.charAt(i));
                    i++;
                }
                
                int val = Integer.valueOf(sb.toString());
                numStack.push(val);
            } else {
                if (opStack.isEmpty() || !hasHigherPrecedence(opStack.peek(), token)) {
                    opStack.push(token);
                    i++;
                } else {
                   calculate(numStack, opStack);
                }
            }
        }
        
        while(!opStack.isEmpty()) {
            calculate(numStack, opStack);
        }
        
        return numStack.pop();
    }
    
    private boolean isNumber(char character) {
        return character >= '0' && character <= '9';
    }
    
    private void calculate(Stack<Integer> numStack, Stack<Character> opStack) {
        int num2 = numStack.pop();
        int num1 = numStack.pop();
        char oprator = opStack.pop();
        
        int result = 0;
        
        switch(oprator) {
            case '+' : result = num1 + num2;
            break;
            
            case '-' : result = num1 - num2;
            break;
            
            case '*' : result = num1 * num2;
            break;
            
            case '/' : result = num1 / num2;
            break;
        }
        
        numStack.push(result);
    }
    
    private boolean hasHigherPrecedence(char str1, char str2) {
        if (str1 == '*'|| str1 == '/') {
            return true;
        }
        
        if ((str1 == '+' || str1 == '-') && (str2 == '+' || str2 == '-')) {
            return true;
        }
        
        return false;
    }
}

Leetcode: Valid Anagram

Given two strings s and t, write a function to determine if t is an anagram of s.
For example,
s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.
Note:
You may assume the string contains only lowercase alphabets.
Understand the problem:
If two strings are anagram iff the sorted format is the same. 

Code (Java):
public class Solution {
    public boolean isAnagram(String s, String t) {
        if (s == null || s.length() == 0) {
            return t == null || t.length() == 0;
        }
        
        if (t == null || t.length() == 0) {
            return s == null || s.length() == 0;
        }
        
        if (s.length() != t.length()) {
            return false;
        }
        
        char[] sArr = s.toCharArray();
        char[] tArr = t.toCharArray();
        
        Arrays.sort(sArr);
        Arrays.sort(tArr);
        
        for (int i = 0; i < sArr.length; i++) {
            if (sArr[i] != tArr[i]) {
                return false;
            }
        }
        
        return true;
    }
}


Leetcode: Delete Node in a Linked List

Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.
Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with value 3, the linked list should become 1 -> 2 -> 4 after calling your function.
Understand the problem:
Since the problem only gives the node to be deleted, it is tricky to solve the problem.

We can duplicate the node to be deleted by copy the node.next val to the node. and remove the node.next. 

Code (Java):
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public void deleteNode(ListNode node) {
        if (node == null) {
            return;
        }
        
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

Leetcode: Lowest Common Ancestor of a Binary Search Tree

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
        _______6______
       /              \
    ___2__          ___8__
   /      \        /      \
   0      _4       7       9
         /  \
         3   5
For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
Understand the problem:
The problem can be solved by either treating the BST as a regular binary tree, or BST. 
For the binary tree solution, we could check out the previous post using divide and conquer solution. 

Now let's take a look at the solution for BST.

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 TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return root;
        }
        
        if (root.val > p.val && root.val < q.val) {
            return root;
        } else if (root.val > p.val && root.val > q.val) {
            return lowestCommonAncestor(root.left, p, q);
        } else if (root.val < p.val && root.val < q.val) {
            return lowestCommonAncestor(root.right, p, q);
        }
        
        return root;
    }
}

Update on 1/27/16:
I think this solution is clearer in the sense that we need to make sure node p and always at left of q.
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || p == null || q == null) {
            return null;
        }
        
        // Make sure p is on the left of q
        if (p.val > q.val) {
            TreeNode temp = p;
            p = q;
            q = temp;
        }
        
        if (root.val >= p.val && root.val <= q.val) {
            return root;
        } else if (root.val > p.val && root.val > q.val) {
            return lowestCommonAncestor(root.left, p, q);
        } else {
            return lowestCommonAncestor(root.right, p, q);
        }
    }
}

Leetcode: Palindrome Linked List

Given a singly linked list, determine if it is a palindrome.
Follow up:
Could you do it in O(n) time and O(1) space?
Understand the problem:
Since the problem asks for O(n) time and O(1) space, we cannot create additional data structure to store the values. The steps to solve the problem are:
  -- 1. Find the middle of the list. 
  -- 2. Reverse the right half of the list. 
  -- 3. Compare the left half and right half.

Code (Java):
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) {
            return true;
        }
        
        int len = getLength(head);
        
        ListNode mid = findMiddle(head);
        
        ListNode newHead;
        
        if (len % 2 == 0) {
            newHead = mid.next;
            mid.next = null;
        } else {
            ListNode dummyNode = new ListNode(mid.val);
            dummyNode.next = mid.next;
            newHead = dummyNode;
        }
        
        // Step 2: reverse the list
        newHead = reverseList(newHead);
        
        // Step 3: compare the list
        ListNode p = head;
        ListNode q = newHead;
        while (p != null && q != null) {
            if (p.val != q.val) {
                return false;
            }
            
            p = p.next;
            q = q.next;
        }
        
        return true;
    }
    
    private int getLength(ListNode head) {
        ListNode p = head;
        int len = 0;
        
        while (p != null) {
            len++;
            p = p.next;
        }
        
        return len;
    }
    
    private ListNode findMiddle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        
        while (fast != null && fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        
        return slow;
    }
    
    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        
        return prev;
    }
}


Leetcode: Power of Two

Given an integer, write a function to determine if it is a power of two.
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.
Understand the problem:
The problem is a bit manipulation problem. 

The basic idea is to bit & with mask 1, and count the number of 1s. Then shift the n to the right until n is 0. If n is power of 2, the number of 1 should be equal to 1. 

Code (Java):
public class Solution {
    public boolean isPowerOfTwo(int n) {
        if (n <= 0) {
            return false;
        }
        
        int count = 0;
        
        while (n > 0) {
            count += (n & 1);
            n = n >> 1;
        }
        
        return count == 1;
    }
}

Another one-line solution:
A number is power of 2 is equalvent to if n & (n - 1) == 0. 

Code (Java):
public class Solution {
    public boolean isPowerOfTwo(int n) {
        if (n <= 0) {
            return false;
        }
        
        return (n & (n - 1)) == 0;
    }
}

Leetcode: Implement Queue using Stacks

Implement the following operations of a queue using stacks.
  • push(x) -- Push element x to the back of queue.
  • pop() -- Removes the element from in front of queue.
  • peek() -- Get the front element.
  • empty() -- Return whether the queue is empty.
Notes:
  • You must use only standard operations of a stack -- which means only push to toppeek/pop from topsize, and is empty operations are valid.
  • Depending on your language, stack may not be supported natively. You may simulate a stack by using a list or deque (double-ended queue), as long as you use only standard operations of a stack.
  • You may assume that all operations are valid (for example, no pop or peek operations will be called on an empty queue).
Understand the problem:
The problem can be solved by using two stacks, stack1 and stack2.
  -- push(x), push an element into stack1. O(1) time complexity.
  -- pop(), check if the stack 2 is empty. If not, pop from stack2. If yes, pop all elements from stack1 and push into stack2. Then pop from stack2. Amortized time complexity is O(1).
  -- peek(). The same as pop().
  -- isEmpty(). Check if both stack1 and stack2 are empty.

Code (Java):
class MyQueue {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    
    public MyQueue() {
        this.stack1 = new Stack<Integer>();
        this.stack2 = new Stack<Integer>();
    }
    // Push element x to the back of queue.
    public void push(int x) {
        stack1.push(x);
    }

    // Removes the element from in front of queue.
    public void pop() {
        if (!stack2.isEmpty()) {
            stack2.pop();
        } else {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
            stack2.pop();
        }
    }

    // Get the front element.
    public int peek() {
        int ret = 0;
        if (!stack2.isEmpty()) {
            ret = stack2.peek();
        } else {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
            ret = stack2.peek();
        }
        
        return ret;
    }

    // Return whether the queue is empty.
    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}

Leetcode: Majority Element II

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run in linear time and in O(1) space.
Hint:
  1. How many majority elements could it possibly have?
  2. Do you have a better hint? Suggest it!
Understand the problem:
Since the problem suggest to use O(1) space solution, we cannot use a hash map to store the visited elements. 

How many elements could it possiblly have? Since the majority number is more than n / 3, the maximal majority elements are 2. 

So we could maintain two candidates and the counters for the candidates, respectively. The rest of the method is the same of the Moore vote algorithm. Note that we need to re-validate again at the end because it is possible that the array does not have any majority elements. 

Code (Java):

public class Solution {
    public List<Integer> majorityElement(int[] nums) {
        List<Integer> result = new ArrayList<Integer>();
        
        if (nums == null || nums.length == 0) {
            return result;
        }
        
        if (nums.length == 1) {
            result.add(nums[0]);
            return result;
        }
        
        int candidate1 = nums[0];
        int candidate2 = 0;
        
        int count1 = 1;
        int count2 = 0;
        
        for (int i = 1; i < nums.length; i++) {
            int num = nums[i];
            if (candidate1 == num) {
                count1++;
            } else if (candidate2 == num) {
                count2++;
            } else if (count1 == 0) {
                candidate1 = num;
                count1 = 1;
            } else if (count2 == 0) {
                candidate2 = num;
                count2 = 1;
            } else {
                count1--;
                count2--;
            }
        }
        
        count1 = 0;
        count2 = 0;
        
        for (int num : nums) {
            if (num == candidate1) {
                count1++;
            } else if (num == candidate2) {
                count2++;
            }
        }
        
        if (count1 > nums.length / 3) {
            result.add(candidate1);
        }
        
        if (count2 > nums.length / 3) {
            result.add(candidate2);
        }
        
        return result;
    }
}



Leetcode: Implement Stack using Queues

mplement the following operations of a stack using queues.
  • push(x) -- Push element x onto stack.
  • pop() -- Removes the element on top of the stack.
  • top() -- Get the top element.
  • empty() -- Return whether the stack is empty.
Notes:
  • You must use only standard operations of a queue -- which means only push to backpeek/pop from frontsize, and is empty operations are valid.
  • Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
  • You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
Update (2015-06-11):
The class name of the Java function had been updated to MyStack instead of Stack.
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and all test cases.
Understand the problem:
We can use two queues, queue1 and queue2.
 -- push(x), push x into queue1. Time complexity O(1)
 -- pop(), dequeue all n - 1 elements and enqueue into queue2. dequeue the last element. 
Swap queue1 and queue2. Time complexity O(n).
 -- top() dequeue all n - 1 elements and enqueue into queue2, dequeue the last element and save the as return, then enqueue it into queue2. Swap queue1 and queue2. Time complexity is O(n).
 -- empty(), check if queue1 is empty. 

Code (Java):
class MyStack {
    private Queue<Integer> queue1;
    private Queue<Integer> queue2;
    
    public MyStack() {
        this.queue1 = new LinkedList<Integer>();
        this.queue2 = new LinkedList<Integer>();
    }
    
    // Push element x onto stack.
    public void push(int x) {
        queue1.offer(x);
    }

    // Removes the element on top of the stack.
    public void pop() {
        while (queue1.size() > 1) {
            queue2.offer(queue1.poll());
        }
        
        queue1.poll();
        
        // Swap queue1 and queue2
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }

    // Get the top element.
    public int top() {
        while (queue1.size() > 1) {
            queue2.offer(queue1.poll());
        }
        
        int ret = queue1.poll();
        queue2.offer(ret);
        
        // Swap queue 1 and queue2
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
        
        return ret;
    }

    // Return whether the stack is empty.
    public boolean empty() {
        return queue1.isEmpty();
    }
}

Tuesday, September 1, 2015

Leetcode: Invert Binary Tree

Invert a binary tree.
     4
   /   \
  2     7
 / \   / \
1   3 6   9
to
     4
   /   \
  7     2
 / \   / \
9   6 3   1
Trivia:
This problem was inspired by this original tweet by Max Howell:
Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.
Understand the problem:
The problem is very easy to understand. Just to re-link root's left child to the right sub-tree, and root's right child to the left sub-tree. Only one thing to note is we must use a temp Node when we do the swap. 

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 TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        
        TreeNode temp = root.left;
        
        root.left = invertTree(root.right);
        root.right = invertTree(temp);
        
        return root;
    }
}

A BFS Solution:
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode invertTree(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        if (root == null) {
            return null;
        }
        
        queue.offer(root);
        
        while (!queue.isEmpty()) {
            TreeNode curr = queue.poll();
            
            if (curr.left != null) {
                queue.offer(curr.left);
            }
            
            if (curr.right != null) {
                queue.offer(curr.right);
            }
            
            TreeNode temp = curr.left;
            curr.left = curr.right;
            curr.right = temp;
        }
        
        return root;
    }
}

Leetcode: Count Complete Tree Nodes

Given a complete binary tree, count the number of nodes.
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
Understand the problem:
First of all, what is a complete binary tree? 
A complete binary tree is a binary tree where each level except for the last level is full. 

A naive solution:
A naive solution is just to traverse the tree and count the number of nodes. The time complexity is O(n). It gets the Time Limit Exceeded. 

A Better Solution:
A better idea is to get the height of the left-most part, and height of the right-most part. If the left height and right height are the same, means the tree is full. Then the number of nodes is 2^h - 1. If not, we recursively count the number of nodes for the left sub-tree and right sub-tree. 

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 countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        int leftHeight = findLeftHeight(root);
        int rightHeight = findRightHeight(root);
        
        if (leftHeight == rightHeight) {
            return (2 << (leftHeight - 1)) - 1;
        }
        
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
    
    private int findLeftHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        int height = 1;
        
        while (root.left != null) {
            height++;
            root = root.left;
        }
        
        return height;
    }
    
    private int findRightHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        int height = 1;
        
        while (root.right != null) {
            height++;
            root = root.right;
        }
        
        return height;
    }
}

The time complexity is O(h^2), because calculating the height of a binary tree takes O(h) time, and it recursively traverse the tree by O(h) time. 
In more detail, in worst case, we need to calculate the height of the tree in 1 + 2 + 3 + 4 + ... + h = O(h^2) time. It is actually 2 * O(h^2) because we need to calculate the left and right height. 

Leetcode: Rectangle Area

Find the total area covered by two rectilinear rectangles in a 2D plane.
Each rectangle is defined by its bottom left corner and top right corner as shown in the figure.
Rectangle Area
Assume that the total area is never beyond the maximum possible value of int.
Credits:
Special thanks to @mithmatt for adding this problem, creating the above image and all test cases.
Understand the problem:
The returned area = area A + area B - overlapped area. 

Code (Java):
public class Solution {
    private class Interval {
        public int start;
        public int end;
        
        public Interval(int s, int e) {
            this.start = s;
            this.end = e;
        }
    }
    
    public int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
        Interval x1 = new Interval(A, C);
        Interval y1 = new Interval(B, D);
        
        Interval x2 = new Interval(E, G);
        Interval y2 = new Interval(F, H);
        
        int x3 = 0;
        int y3 = 0;
        
        if (x1.start <= x2.start) {
            if (x1.end > x2.start) {
                x3 = Math.min(x1.end, x2.end) - Math.max(x1.start, x2.start);
            }
        } else {
            if (x1.start < x2.end) {
                x3 = Math.min(x1.end, x2.end) - Math.max(x1.start, x2.start);
            }
        }
        
        if (y1.start < y2.start) {
            if (y1.end > y2.start) {
                y3 = Math.min(y1.end, y2.end) - Math.max(y1.start, y2.start);
            }
        } else {
            if (y1.start < y2.end) {
                y3 = Math.min(y1.end, y2.end) - Math.max(y1.start, y2.start);
            }
        }
        
        int overlappedArea = x3 * y3;
        
        int area1 = (x1.end - x1.start) * (y1.end - y1.start);
        int area2 = (x2.end - x2.start) * (y2.end - y2.start);
        
        return area1 + area2 - overlappedArea;
    }
}

A neat code:
public int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
    if(C<E||G<A )
        return (G-E)*(H-F) + (C-A)*(D-B);
 
    if(D<F || H<B)
        return (G-E)*(H-F) + (C-A)*(D-B);
 
    int right = Math.min(C,G);
    int left = Math.max(A,E);
    int top = Math.min(H,D);
    int bottom = Math.max(F,B);
 
    return (G-E)*(H-F) + (C-A)*(D-B) - (right-left)*(top-bottom);
}

Leetcode: House Robber II

Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place arearranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.
Understand the problem:
The problem is similar to the last one. The only difference is we can either 
i. Not rob the last one
ii. Not rob the first one.
and calculate the maximum. 

Code (Java):
public class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        if (nums.length == 1) {
            return nums[0];
        }
        
        int n = nums.length;
        // Rob the first house, not the last one. 
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = nums[0];
        
        for (int i = 2; i < n; i++) {
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i - 1]);
        }
        
        dp[n] = dp[n - 1];
        
        // No rob the first, might or may not rob  the last one
        int[] dr = new int[n + 1];
        dr[0] = 0;
        dr[1] = 0;
        
        for (int i = 2; i < n + 1; i++) {
            dr[i] = Math.max(dr[i - 1], dr[i - 2] + nums[i - 1]);
        }
        
        return Math.max(dp[n], dr[n]);
    }
}