Showing posts with label DP. Show all posts
Showing posts with label DP. Show all posts

Wednesday, December 5, 2018

727. Minimum Window Subsequence

727Minimum Window Subsequence
Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequence of W.
If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple such minimum-length windows, return the one with the left-most starting index.
Example 1:
Input: 
S = "abcdebdde", T = "bde"
Output: "bcde"
Explanation: 
"bcde" is the answer because it occurs before "bdde" which has the same length.
"deb" is not a smaller window because the elements of T in the window must occur in order.

Note:
  • All the strings in the input will only contain lowercase letters.
  • The length of S will be in the range [1, 20000].
  • The length of T will be in the range [1, 100].
------------------------
Solution #1, 指针
找到一个匹配之后,以结尾为起始点,倒退着往前找。这样找到的是在[i, j]里最短的符合要求的substring。最坏结果是找到跟原来一摸一样的。
O(m * n) time. 对Complexity的需要研究一下

ref: https://leetcode.com/problems/minimum-window-subsequence/discuss/109356/JAVA-two-pointer-solution-(12ms-beat-100)-with-explaination
class Solution {
    public String minWindow(String s, String t) {
        int si = 0, ti = 0;
        String rt = s + "123";
        while (si < s.length()) {
            if (s.charAt(si) == t.charAt(ti)) {
                if (ti == t.length() - 1) {
                    int end = si;                    
                    while (ti >= 0) {
                        while (s.charAt(si) != t.charAt(ti)) {
                            si--;
                        }
                        ti--;
                        si--;
                    }
                    
                    si++;
                    if (rt.length() > end - si + 1) {
                        rt = s.substring(si, end + 1);
                    }
                }
                ti++;
            }
            
            si++;
        }
        
        return rt.equals(s + "123") ? "" : rt;
    }
}

Solution #2, DP
dp[i][j] = k, i为T的index,j为S的index,k为以[0,i],[0,j]这2段substring最小的起点在s上
如果s[j] == t[i], dp[i][j]那可以借用dp[i - 1][j - 1]时的起点
如果s[j] != t[i],可以借用dp[i][j - 1]

注意dp的初始赋值
class Solution {
    public String minWindow(String s, String t) {
        int n = s.length(), m = t.length();
        int[][] dp = new int[m][n];
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == t.charAt(0)) dp[0][i] = i;
            else if (i > 0) dp[0][i] = dp[0][i - 1];
            else dp[0][i] = -1;
        }

        for (int i = 1; i < m; i++) {
            dp[i][0] = -1;
        }

        for (int i = 1; i < m; i++) {
            for (int j = 1 ; j < n; j++) {
                if (i > j) dp[i][j] = -1;
                else {
                    if (t.charAt(i) == s.charAt(j)) {
                        dp[i][j] = dp[i - 1][j - 1];
                    }else {
                        dp[i][j] = dp[i][j - 1];
                    }
                }
            }
        }

        int min = n;
        String rt = "";
        for (int i = 0; i < n; i++) {
            if (dp[m - 1][i] == -1) continue;
            if (min > i - dp[m - 1][i] + 1) {
                rt = s.substring(dp[m - 1][i], i + 1);
                min = i - dp[m - 1][i] + 1;
            }
        }

        return rt;
    }
}

Sunday, November 18, 2018

374. Guess Number Higher or Lower, 375. Guess Number Higher or Lower II

374Guess Number Higher or Lower
We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.
However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.
Example:
n = 10, I pick 8.

First round:  You guess 5, I tell you that it's higher. You pay $5.
Second round: You guess 7, I tell you that it's higher. You pay $7.
Third round:  You guess 9, I tell you that it's lower. You pay $9.

Game over. 8 is the number I picked.

You end up paying $5 + $7 + $9 = $21.
Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.
----------------------

/* The guess API is defined in the parent class GuessGame.
   @param num, your guess
   @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
      int guess(int num); */

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int left = 1, right = n;
        
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            int rt = guess(mid);
            if (rt == 0) return mid;
            if (rt > 0) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        
        return left;
    }
}

375Guess Number Higher or Lower II
We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.
However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.
Example:
n = 10, I pick 8.

First round:  You guess 5, I tell you that it's higher. You pay $5.
Second round: You guess 7, I tell you that it's higher. You pay $7.
Third round:  You guess 9, I tell you that it's lower. You pay $9.

Game over. 8 is the number I picked.

You end up paying $5 + $7 + $9 = $21.
Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.
-----------------------------
题意有点绕:找一个花费最小的通解
brute force的算法是枚举所有的可能性,找出最小(最优)的解。
给定[start, end], 猜i点之后的cost是cost[i] = i + Math.max(cost[start, i - end], cost[i + 1, end]), 取2者中间最大是因为不能确定最终结果在左还是在右
ref: https://leetcode.com/problems/guess-number-higher-or-lower-ii/solution/

Solution #1 DP 是对brute force的优化
重点:这题的2维DP是按对角线来填充,因为[len]是基于[len - i]...[len - 1]
以后写dp要理解其本身的通项公式
O(n^3)
class Solution {
    public int getMoneyAmount(int n) {
        int[][] dp = new int[n + 1][n + 1];
        
        for (int len = 2; len <= n; len++) {
            for (int start = 1; start < n - len + 2; start++) {
                int min = Integer.MAX_VALUE;
                for (int i = start; i <= start + len - 1; i++) {
                    
                    int v = 0;
                    if (i == start + len - 1) {
                        v = i + dp[start][i - 1];
                    }else 
                        v = i + Math.max(dp[start][i - 1], dp[i + 1][start + len - 1]);
                    
                    min = Math.min(min, v);
                }
                dp[start][start + len - 1] = min;
            }
        }
        
        return dp[1][n];
    }
}
进一步优化: [start, (start + end) / 2] 永远比 [(start + end) / 2, end]小,所以只需计算后半部分。BigO不变

Monday, November 12, 2018

818. Race Car

818Race Car
Your car starts at position 0 and speed +1 on an infinite number line.  (Your car can go into negative positions.)
Your car drives automatically according to a sequence of instructions A (accelerate) and R (reverse).
When you get an instruction "A", your car does the following: position += speed, speed *= 2.
When you get an instruction "R", your car does the following: if your speed is positive then speed = -1 , otherwise speed = 1.  (Your position stays the same.)
For example, after commands "AAR", your car goes to positions 0->1->3->3, and your speed goes to 1->2->4->-1.
Now for some target position, say the length of the shortest sequence of instructions to get there.
Example 1:
Input: 
target = 3
Output: 2
Explanation: 
The shortest instruction sequence is "AA".
Your position goes from 0->1->3.
Example 2:
Input: 
target = 6
Output: 5
Explanation: 
The shortest instruction sequence is "AAARA".
Your position goes from 0->1->3->7->7->6.

Note:
  • 1 <= target <= 10000.
---------------------------
Solution #1, BFS 暴解,内存不不够 case: 330

O(2^n)
class Solution {
    public int racecar(int target) {
        Queue<Node> que = new LinkedList<>();
        Node root = new Node(0, 1, 0);
        que.add(root);
        
        while (!que.isEmpty()) {
            Node node = que.poll();
            if (node.pos == target) return node.len;
            que.add(new Node(node.pos + node.speed, node.speed * 2, node.len + 1));
            que.add(new Node(node.pos, node.speed > 0 ? -1 : 1, node.len + 1));
        }
        
        return 0;
    }
    
    class Node{
        public int pos;
        public int speed;
        public int len;
        public Node(int pos, int speed, int len) {
            this.pos = pos;
            this.speed = speed;
            this.len = len;
        }
    }
}

Solution #2, 加了优化 关键在于剪枝:Math.abs(nextPos - target) <= target. 因为起点跟target的距离就是target,如果比这个还远的话,那最终的步数肯定会超过,没有意义,所以要略掉O (n * log n), n为target的⼤小。速度只有log n种可能,因为速度永远是2的幂次⽅ O(n * log n) 空间,最坏情况是把所有pos和speed的组合都放在queue⾥

class Solution {
    public int racecar(int target) {
        Queue<Node> que = new LinkedList<>();
        Node root = new Node(0, 1, 0);
        que.add(root);
        Set<String> visited = new HashSet<>();
        visited.add("0#1");
        visited.add("0#-1");
        
        while (!que.isEmpty()) {
            Node node = que.poll();
            if (node.pos == target) return node.len;
            int nextPos = node.pos + node.speed;
            String key1 = nextPos  + "#" + node.speed *2;
            if (!visited.contains(key1) && Math.abs(nextPos - target) <= target) {
                que.add(new Node(nextPos, node.speed * 2, node.len + 1));
                visited.add(key1);                
            }
                
            String key2 = node.pos + "#" + (node.speed > 0 ? -1 : 1);
            if (!visited.contains(key2)) {
                que.add(new Node(node.pos, node.speed > 0 ? -1 : 1, node.len + 1));
                visited.add(key2);
            }
        }
        
        return 0;
    }
    
    class Node{
        public int pos;
        public int speed;
        public int len;
        public Node(int pos, int speed, int len) {
            this.pos = pos;
            this.speed = speed;
            this.len = len;
        }
    }
}

Solution #3 rec + memoiz1tion 暴力枚举。 分3种情况:

  1. 刚好⾛到,target == pos,target刚好是2的幂次⽅
  2. 走过头一步,target < pos (两步就没有必要了,看Solution#2的剪枝) 
  3. ⾛i步回头, 再⾛j步回头, i 属于[0, target], j 属于 [0, target - pos]. 注意变量的取值 

ref: https://leetcode.com/problems/r1ce-c1r/discuss/124326/Summ1ry-of-the-BFS-1nd-DP-solutions-with-intuitive-expl1n1tion

class Solution {
    public int racecar(int target) {
        int[] dp = new int[target + 1];
        Arrays.fill(dp, - 1);
        dp[0] = 0;
        return dfs(target, dp);
    }
    
    private int dfs(int target, int[] dp) {
        if (dp[target] >= 0) return dp[target];
        
        dp[target] = Integer.MAX_VALUE;
        int speed = 1, pos = 0, times = 0;
        for (; pos < target; pos += speed, speed <<= 1, times++) {
            
            for (int revPos = 0, revSpeed = 1, revTimes = 0; revPos < pos; revPos += revSpeed, revSpeed <<= 1, revTimes++) {
                dp[target] = Math.min(dp[target], times + 2 + revTimes + dfs(revPos + target - pos, dp));
            }
        }
        
        if (target == pos) {
            dp[target] = Math.min(dp[target], times);    
        }else {
            dp[target] = Math.min(dp[target], times + 1 + dfs(pos - target, dp));
        }
        
        return dp[target];
    }
}

Solution #4 iterative的⽅法,ToDo

Saturday, October 6, 2018

568. Maximum Vacation Days

568Maximum Vacation Days
LeetCode wants to give one of its best employees the option to travel among N cities to collect algorithm problems. But all work and no play makes Jack a dull boy, you could take vacations in some particular cities and weeks. Your job is to schedule the traveling to maximize the number of vacation days you could take, but there are certain rules and restrictions you need to follow.
Rules and restrictions:
  1. You can only travel among N cities, represented by indexes from 0 to N-1. Initially, you are in the city indexed 0 on Monday.
  2. The cities are connected by flights. The flights are represented as a N*N matrix (not necessary symmetrical), called flightsrepresenting the airline status from the city i to the city j. If there is no flight from the city i to the city j, flights[i][j] = 0; Otherwise, flights[i][j] = 1. Also, flights[i][i] = 0 for all i.
  3. You totally have K weeks (each week has 7 days) to travel. You can only take flights at most once per day and can only take flights on each week's Monday morning. Since flight time is so short, we don't consider the impact of flight time.
  4. For each city, you can only have restricted vacation days in different weeks, given an N*K matrix called days representing this relationship. For the value of days[i][j], it represents the maximum days you could take vacation in the city i in the week j.
You're given the flights matrix and days matrix, and you need to output the maximum vacation days you could take during K weeks.
Example 1:
Input:flights = [[0,1,1],[1,0,1],[1,1,0]], days = [[1,3,1],[6,0,3],[3,3,3]]
Output: 12
Explanation: 
Ans = 6 + 3 + 3 = 12. 

One of the best strategies is:
1st week : fly from city 0 to city 1 on Monday, and play 6 days and work 1 day. 
(Although you start at city 0, we could also fly to and start at other cities since it is Monday.) 
2nd week : fly from city 1 to city 2 on Monday, and play 3 days and work 4 days.
3rd week : stay at city 2, and play 3 days and work 4 days.
Example 2:
Input:flights = [[0,0,0],[0,0,0],[0,0,0]], days = [[1,1,1],[7,7,7],[7,7,7]]
Output: 3
Explanation: 
Ans = 1 + 1 + 1 = 3. 

Since there is no flights enable you to move to another city, you have to stay at city 0 for the whole 3 weeks. 
For each week, you only have one day to play and six days to work. 
So the maximum number of vacation days is 3.
Example 3:
Input:flights = [[0,1,1],[1,0,1],[1,1,0]], days = [[7,0,0],[0,7,0],[0,0,7]]
Output: 21
Explanation:
Ans = 7 + 7 + 7 = 21

One of the best strategies is:
1st week : stay at city 0, and play 7 days. 
2nd week : fly from city 0 to city 1 on Monday, and play 7 days.
3rd week : fly from city 1 to city 2 on Monday, and play 7 days.
Note:
  1. N and K are positive integers, which are in the range of [1, 100].
  2. In the matrix flights, all the values are integers in the range of [0, 1].
  3. In the matrix days, all the values are integers in the range [0, 7].
  4. You could stay at a city beyond the number of vacation days, but you should work on the extra days, which won't be counted as vacation days.
  5. If you fly from the city A to the city B and take the vacation on that day, the deduction towards vacation days will count towards the vacation days of city B in that week.
  6. We don't consider the impact of flight hours towards the calculation of vacation days.
--------------------------------
典型的DP,这次直接给iterative的解法了。
dp[i][k] (0<= i <= N - 1, 0 <= k <= K - 1) 表示从城市i出发,在第k周的周一能得到的最大值
因为dp[i][k]仅依赖于dp[i][k + 1], 所以一维dp就够了
O(K * N ^ 2)
class Solution {
    public int maxVacationDays(int[][] flights, int[][] days) {
        int N = flights.length, K = days[0].length;
        int[] dp = new int[N];
        
        for (int k = K - 1; k >= 0; k--) {
            int[] tmp = new int[N];
            
            for (int i = 0; i < N; i++) {
                tmp[i] = days[i][k] + dp[i];
                for (int j = 0; j < N; j++) {
                    if (flights[i][j] == 0) continue;
                    tmp[i] = Math.max(tmp[i], days[j][k] + dp[j]);
                }
            }
            dp = tmp;
        }
        
        return dp[0];
    }
}

Sunday, September 30, 2018

688. Knight Probability in Chessboard

688Knight Probability in Chessboard
On an NxN chessboard, a knight starts at the r-th row and c-th column and attempts to make exactly K moves. The rows and columns are 0 indexed, so the top-left square is (0, 0), and the bottom-right square is (N-1, N-1).
A chess knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal direction, then one square in an orthogonal direction.

Each time the knight is to move, it chooses one of eight possible moves uniformly at random (even if the piece would go off the chessboard) and moves there.
The knight continues moving until it has made exactly K moves or has moved off the chessboard. Return the probability that the knight remains on the board after it has stopped moving.
Example:
Input: 3, 2, 0, 0
Output: 0.0625
Explanation: There are two moves (to (1,2), (2,1)) that will keep the knight on the board.
From each of those positions, there are also two moves that will keep the knight on the board.
The total probability the knight stays on the board is 0.0625.
Note:




  • N will be between 1 and 25.
  • K will be between 0 and 100.
  • The knight always initially starts on the board.

  • -----------------------
    典型的DP,按套路一路推理

    Solution #1 超时
    class Solution {
        
        public double knightProbability(int N, int K, int r, int c) {
            int total = 1;
            for (int i = 0; i < K; i++) {
                total *= 8;
            }
           
            return dfs(N, K, r, c) / total;
        }
        
        public double dfs(int N, int K, int r, int c) {
            if (r < 0 || r >= N || c < 0 || c >= N) {
                return 0;
            }
    
            if (K == 0) {
                return 1;
            }
            
            return  dfs(N, K - 1, r - 2, c - 1) +
                + dfs(N, K - 1, r - 2, c + 1)
                + dfs(N, K - 1, r - 1, c - 2)
                + dfs(N, K - 1, r - 1, c + 2)
                + dfs(N, K - 1, r + 1, c - 2)
                + dfs(N, K - 1, r + 1, c + 2)
                + dfs(N, K - 1, r + 2, c - 1)
                + dfs(N, K - 1, r + 2, c + 1);
        }
    }
    

    Solution #2 Memoization
    O(N^2 * K) 时间
    class Solution {
        private int[] dr = {-2, -2, -1, -1, 1, 1, 2, 2};
        private int[] dc = {-1, 1, -2, 2, -2, 2, -1, 1};
             
        public double knightProbability(int N, int K, int r, int c) {
            
            double[][][] dp = new double[N][N][K];
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++)
                    Arrays.fill(dp[i][j], -1);
            }
            double a = dfs(N, K, r, c, dp);
            return  a / Math.pow(8, K);
        }
        
        public double dfs(int N, int K, int r, int c, double[][][] dp) {
            if (r < 0 || r >= N || c < 0 || c >= N) {
                return 0;
            }
            
            if (K == 0) {
                return 1;
            }
            if (dp[r][c][K - 1] != -1) return dp[r][c][K - 1];
    
            double total = 0;
            for (int i = 0; i < 8; i++) {
                total += dfs(N, K - 1, r + dr[i], c + dc[i], dp);
            }
            
            dp[r][c][K - 1] = total;
            return total;
        }
    }
    

    Solution #3 DP, 思路同上。
    因为[k]仅依赖于[k - 1], 所以用2个2维数组可以交替使用,不用3维
    O(N^2 * K) 时间,O(N^2) 空间
    class Solution {
        private int[] dr = {-2, -2, -1, -1, 1, 1, 2, 2};
        private int[] dc = {-1, 1, -2, 2, -2, 2, -1, 1};
             
        public double knightProbability(int N, int K, int r, int c) {
            
            double[][] dp1 = new double[N][N];
            double[][] dp2 = new double[N][N];    
            dp1[r][c] = 1;
            
            for (int k = 0; k < K; k++) {
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < N; j++) {
                        if (dp1[i][j] > 0) {
                            for (int d = 0; d < 8; d++) {
                                helper(N, i, j, i + dr[d], j + dc[d], dp1, dp2);   
                            }                
                            dp1[i][j] = 0;
                        }
                    }
                }
                double[][] tmp = dp1;
                dp1 = dp2;
                dp2 = tmp;
            }
            
            double total = 0;
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) total += dp1[i][j];
            }
            
            return  total / Math.pow(8, K);
        }
        
        public void helper(int N, int r1, int c1, int r2, int c2, double[][] dp1, double[][] dp2) {
            
            if (r2 < 0 || r2 >= N || c2 < 0 || c2 >= N) {
                return ;
            }
            dp2[r2][c2] += dp1[r1][c1];
        }
    }
    

    Thursday, August 30, 2018

    403. Frog Jump

    403Frog Jump
    A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.
    Given a list of stones' positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.
    If the frog's last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.
    Note:
    • The number of stones is ≥ 2 and is < 1,100.
    • Each stone's position will be a non-negative integer < 231.
    • The first stone's position is always 0.
    Example 1:
    [0,1,3,5,6,8,12,17]
    
    There are a total of 8 stones.
    The first stone at the 0th unit, second stone at the 1st unit,
    third stone at the 3rd unit, and so on...
    The last stone at the 17th unit.
    
    Return true. The frog can jump to the last stone by jumping 
    1 unit to the 2nd stone, then 2 units to the 3rd stone, then 
    2 units to the 4th stone, then 3 units to the 6th stone, 
    4 units to the 7th stone, and 5 units to the 8th stone.
    
    Example 2:
    [0,1,2,3,4,8,9,11]
    
    Return false. There is no way to jump to the last stone as 
    the gap between the 5th and 6th stone is too large.
    --------------------------------
    Solution #1, brute force. Time limit exceeded
    O(3^n)
    class Solution {
        public boolean canCross(int[] stones) {
            Map<Integer, Integer> map = getMap(stones);
            return rec(map, stones, 1, 1);
        }
        
        private boolean rec(Map<Integer, Integer> map, int[] stones, int stone, int k) {
            if (k == 0 || !map.containsKey(stone)) return false;
            if (map.get(stone) == stones.length - 1) return true;
            
            return rec(map, stones, stone + k - 1, k - 1)
                || rec(map, stones, stone + k, k)
                || rec(map, stones, stone + k + 1, k + 1);
        }
        
        private Map<Integer, Integer> getMap(int[] stones) {
            Map<Integer, Integer> map = new HashMap<>();
            for (int i = 0; i < stones.length; i++) {
                map.put(stones[i], i);
            }
            
            return map;
        }
    }
    

    Solution #2, DP - Memoization
    O(n^2 * m), m为计算key的复杂度,ToDo: java这块转换代码的实现和复杂度得深入了解下
    如果用一些hashing算法的话,应该可以把m压缩到O(1), 这样总体保持O(n^2)
    或者(ToDo),用一个n * n的2d array,n为stone的数量。因为步数k肯定会是小于总的stone的数量
    class Solution {
        public boolean canCross(int[] stones) {
            Map<Integer, Integer> map = getMap(stones);
            Map<String, Boolean> dp = new HashMap<>();
            return rec(map, stones, 1, 1, dp);
        }
        
        private boolean rec(Map<Integer, Integer> map, int[] stones, int stone, int k, Map<String, Boolean> dp) {
            if (k == 0 || !map.containsKey(stone)) return false;
            if (map.get(stone) == stones.length - 1) return true;
            
            String key = Integer.toString(stone) + "#" + Integer.toString(k);
            if (dp.containsKey(key)) {
                return dp.get(key);
            }
            
            boolean flag = rec(map, stones, stone + k - 1, k - 1, dp)
                || rec(map, stones, stone + k, k, dp)
                || rec(map, stones, stone + k + 1, k + 1, dp);
            
            dp.put(key,flag);
            return flag;
        }
        
        private Map<Integer, Integer> getMap(int[] stones) {
            Map<Integer, Integer> map = new HashMap<>();
            for (int i = 0; i < stones.length; i++) {
                map.put(stones[i], i);
            }
            
            return map;
        }
    }
    
    Solution #3, iterative DP. 用#2的思路,但是第2维存的是Set,因为要保证唯一性
    Map里存的是(stone -> 到达当前stone上一步所用的step). 画一个2维矩阵图能帮助理解,这里就懒得发上来了。
    class Solution {
        public boolean canCross(int[] stones) {
            Map<Integer, Set<Integer>> map = getMap(stones);
            
            if (!map.containsKey(1)) return false;
            map.get(1).add(1);
            for (int i = 1; i < stones.length - 1; i++) {
                
                int stone = stones[i];
                for (Integer step : map.get(stone)) {
                    if (step - 1 > 0 && map.containsKey(stone + step - 1)) {
                        map.get(stone + step - 1).add(step - 1);
                    }
                    if (map.containsKey(stone + step)) {
                        map.get(stone + step).add(step);
                    }
                    if (map.containsKey(stone + step + 1)) {
                        map.get(stone + step + 1).add(step + 1);
                    }
                }
            }
            
            return !map.get(stones[stones.length - 1]).isEmpty();
        }
        
        private Map<Integer, Set<Integer>> getMap(int[] stones) {
            Map<Integer, Set<Integer>> map = new HashMap<>();
            for (int stone : stones) {
                map.put(stone, new HashSet<>());
            }
            
            return map;
        }
    }
    

    Thursday, July 19, 2018

    494. Target Sum

    494Target Sum
    You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol.
    Find out how many ways to assign symbols to make sum of integers equal to target S.
    Example 1:
    Input: nums is [1, 1, 1, 1, 1], S is 3. 
    Output: 5
    Explanation: 
    
    -1+1+1+1+1 = 3
    +1-1+1+1+1 = 3
    +1+1-1+1+1 = 3
    +1+1+1-1+1 = 3
    +1+1+1+1-1 = 3
    
    There are 5 ways to assign symbols to make the sum of nums be target 3.
    
    Note:
    1. The length of the given array is positive and will not exceed 20.
    2. The sum of elements in the given array will not exceed 1000.
    3. Your output answer is guaranteed to be fitted in a 32-bit integer.
    ---------------------------
    Solution #1, straightforward recursion
    O(2^n)
    class Solution {
        public int findTargetSumWays(int[] nums, int S) {
            return helper(nums, 0, S);
        }
        
        private int helper(int[] nums, int index, int sum) {
            if (index == nums.length && sum == 0) return 1;
            if (index >= nums.length) return 0;
            
            return helper(nums, index + 1, sum - nums[index]) 
                + helper(nums, index + 1, sum + nums[index]);
        }
    }
    
    Solution #2
    Memoization
    会发现此题有重复的子问题,DP可解:
    + 1 - 1 [11] 跟 - 1 + 1 [11], 括号内为重复
    + 1 + 2 - 3 [4 5 6] 跟 - 1 - 2 + 3 [4 5 6]

    很难直接从递归就看出它的复杂度,因为取决于生成不同sum的个数。树的深度为nums的长度
    class Solution {
        public int findTargetSumWays(int[] nums, int S) {
            return helper(nums, 0, S, new HashMap());
        }
        
        private int helper(int[] nums, int index, int sum, Map cache) {
            if (index == nums.length && sum == 0) return 1;
            if (index >= nums.length) return 0;
            
            String plusKey = index + "+" + sum;
            int plus = 0;
            if (cache.containsKey(plusKey)) {
                plus = cache.get(plusKey);
            } else {
                plus = helper(nums, index + 1, sum - nums[index], cache);    
                cache.put(plusKey, plus);
            }
            
            String minusKey = index + "-" + sum;
            int minus = 0;
            if (cache.containsKey(minusKey)) {
                minus = cache.get(minusKey);
            } else {
                minus = helper(nums, index + 1, sum + nums[index], cache);   
                cache.put(minusKey, minus);
            }        
            
            return plus + minus;
        }
    }
    
    Solution #3,遍历DP,跟上面Memoization一样,每一个小问题都可以用(index, sum)的组合来表示
    O(n * m) 时间,n为nums的changdu,m为最长的sums的可能性
    class Solution {
        public int findTargetSumWays(int[] nums, int S) {
            int n = nums.length;
            Map sums = new HashMap<>();
            Map newSums = new HashMap<>();
            sums.put(S, 1);
            
            for (int i = n - 1; i >= 0; i--) {
                int num = nums[i];
                
                for (Map.Entry pair : sums.entrySet()) {
                    int sum1 = pair.getKey() - num;
                    addToNewMap(newSums, sum1, pair.getValue());
                    
                    int sum2 = pair.getKey() + num;
                    addToNewMap(newSums, sum2, pair.getValue());
                }
                
                Map tmp = sums;
                sums.clear();
                sums = newSums;
                newSums = tmp;
            }
            
            return sums.getOrDefault(0, 0);
        }
        
        private void addToNewMap(Map cur, int sum, int value) {
            if (!cur.containsKey(sum)) {
                cur.put(sum, 0);
            }
            cur.put(sum, value + cur.get(sum));
        }
    }
    

    其他:因为题目已经给定所有数的sum不会超过1000,所以有一种方法是开一个大小为1000(?或者2000 + 1,因为要考虑0和负数)的数组,每次遍历一下就是了。
    但是以上我的方法不会被1000所限制。

    Update: 发现Solution #2-#3原来就是所谓的subset sum

    Sunday, September 20, 2015

    Day 128, #256 #265 #267 #273 Paint House, Paint House II, Palindrome Permutation II, Integer to English Words

    Paint House
    There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color.
    The cost of painting each house with a certain color is represented by a n x 3 cost matrix. For example, costs[0][0] is the cost of painting house 0 with color red;costs[1][2] is the cost of painting house 1 with color green, and so on... Find the minimum cost to paint all houses.
    Note:
    All costs are positive integers.
    -----------------------------------------
    方程式:
    递归:超时,可加memoization
    class Solution {
    public:
        int helper(vector<vector<int>>& costs, int index,int pre) {
            if (index == costs.size()) return 0;
            int min1 = INT_MAX,min2 = INT_MAX,min3 = INT_MAX;
            if (pre != 0) {
                min1 = costs[index][0] + helper(costs,index + 1,0);
            }
            if (pre != 1) {
                min2 = costs[index][1] + helper(costs,index + 1,1);
            }
            if (pre != 2) {
                min3 = costs[index][2] + helper(costs,index + 1,2);
            }
            
            return min(min(min2,min1),min3);
        }
    
        int minCost(vector<vector<int>>& costs) {
            return helper(costs,0,-1);
        }
    };
    

    DP:
    3个array,dp[k][i] = 为在第i个房子涂k的颜色所需要的总花费
    dp[0][i] = costs[i][0] + min(dp[1][i - 1],dp[2][i - 1]);
    其他2个颜色类同

    以下方法已经做过空间优化
    class Solution {
    public:
        int minCost(vector<vector<int>>& costs) {
            int n = costs.size();
            if (n == 0) return 0;
            int dp0 = costs[0][0];
            int dp1 = costs[0][1];
            int dp2 = costs[0][2];
            
            for (int i = 1; i < n; i++) {
                int t0 = dp0, t1 = dp1, t2 = dp2;
                dp0 = costs[i][0] + min(t1,t2);
                dp1 = costs[i][1] + min(t2,t0);
                dp2 = costs[i][2] + min(t1,t0);
            }
    
            return min(min(dp0,dp1),dp2);
        }
    };
    

    Paint House II
    There are a row of n houses, each house can be painted with one of the k colors. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color.
    The cost of painting each house with a certain color is represented by a n x k cost matrix. For example, costs[0][0] is the cost of painting house 0 with color 0; costs[1][2] is the cost of painting house 1 with color 2, and so on... Find the minimum cost to paint all houses.
    Note:
    All costs are positive integers.
    Follow up:
    Could you solve it in O(nk) runtime?
    ------------------------------------------
    2个variable保存上一次涂房子的最小的2个值,first是值,second是颜色

    class Solution {
    public:
        int minCostII(vector>& costs) {
            int n = costs.size();
            if (n == 0) return 0;
            int k = costs[0].size();
            vector dp = costs[0];
            int minCost = INT_MAX;
            
            for (int i = 1; i < n; i++) {
                // pair of cost - color
                pair min1 = make_pair(INT_MAX,-1);
                pair min2 = make_pair(INT_MAX,-1);
                // find the smallest two values from previous painting job
                for (int j = 0; j < k; j++) {
                    if (dp[j] < min1.first) {
                        min2 = min1;
                        min1.first = dp[j];
                        min1.second = j;
                    }else if (dp[j] < min2.first) {
                        min2.first = dp[j];
                        min2.second = j;
                    }
                }
                
                for (int j = 0; j < k; j++) {
                    if (j == min1.second) {
                        dp[j] = costs[i][j] + min2.first;
                    }else {
                        dp[j] = costs[i][j] + min1.first;
                    }
                }
            }
        
            for (int i = 0; i < k; i++) {
                minCost = min(minCost,dp[i]);
            }
            
            return minCost;
        }
    };
    

    Palindrome Permutation II
     Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empty list if no palindromic permutation could be form.
    For example:
    Given s = "aabb", return ["abba", "baab"].
    Given s = "abc", return [].
    Hint:

    1. If a palindromic permutation exists, we just need to generate the first half of the string.
    2. To generate all distinct permutations of a (half of) string, use a similar approach from: Permutations II or Next Permutation.
    ------------------------------
    #1 检测所给string是否可生成pal, 跟I一样
    #2 典型permutation
    class Solution {
    public:
        vector<int> collect(string s,string &single) {
            vector<int> count(256,0);
            for (int i = 0; i < s.length(); i++) {
                count[s[i]]++;
            }
            
            for (int i = 0; i < 256; i++) {
                if (count[i] % 2 == 1) {
                    if (single == "") {
                        single += i;
                    }else {
                        vector<int> t;
                        return t;
                    }
                }
            }
            
            return count;
        }
    
        void rec(vector<string> &rt,vector<int> &count,string s,int total,string single) {
            if (total == 0) {
                string t = s;
                reverse(t.begin(),t.end());
                rt.push_back(s + single + t);
                return;
            }
            
            for (int i = 0; i < 256; i++) {
                if (count[i] < 2) continue;
                string t = s;
                t += i;
                count[i] -= 2;
                rec(rt,count,t,total - 1,single);
                count[i] += 2;
            }
        }
    
        vector<string> generatePalindromes(string s) {
            vector<string> rt;
            string single = "";
            vector<int> count = collect(s,single);
            if (count.size() == 0) return rt;
            rec(rt,count,"",s.length() / 2,single);
            return rt;
        }
    };
    

    Java
    class Solution {
        public List<String> generatePalindromes(String s) {
            List<String> rt = new ArrayList<>();
            int[] map = new int[128];
            int odd = 0;
            
            for (int i = 0; i < s.length(); i++) {
                map[s.charAt(i)] += 1;
                if (map[s.charAt(i)] % 2 == 1) odd++;
                else odd--;
            }
            
            if (odd > 1) return rt;
            
            String mid = "";
            for (int i = 0; i < 128; i++) {
                if (map[i] % 2 == 1) mid += (char)i;
            }
    
            perm(rt, "", s.length() / 2, mid, map);
            
            return rt;
        }
        
        private void perm(List<String> rt, String curS, int total, String mid, int[] map) {
            if (total == 0) {
                rt.add(curS + mid + new StringBuilder(curS).reverse().toString());
                return;
            }
            
            for (int i = 0; i < 128; i++) {
                if (map[i] < 2) continue;
                map[i] -= 2;
                perm(rt, curS + (char)i, total - 1, mid, map);
                map[i] += 2;
            }
        }
    }
    
    Integer to English Words
    Convert a non-negative integer to its english words representation. Given input is guaranteed to be less than 231 - 1.
    For example,
    123 -> "One Hundred Twenty Three"
    12345 -> "Twelve Thousand Three Hundred Forty Five"
    1234567 -> "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven"
    Hint:
    1. Did you see a pattern in dividing the number into chunk of words? For example, 123 and 123000.
    2. Group the number by thousands (3 digits). You can write a helper function that takes a number less than 1000 and convert just that chunk to words.
    3. There are many edge cases. What are some good test cases? Does your code work with input such as 0? Or 1000010? (middle chunk is zero and should not be printed out)
    ----------------------------------------------------------------
    注意空格
    class Solution {
    public:
        string translate(vector<string> &ones,vector<string> &oneTens,vector<string> &tens,vector<string> &ends,int nums,string end) {
            string rt = "";
            if (nums >= 100) {
                rt += ones[nums / 100 - 1] + " Hundred";
                nums %= 100;
            }
            
            if (nums >= 10) {
                if (rt != "") rt += " ";
                if (nums <= 19) {
                    rt += oneTens[nums % 10];
                    return rt + end;
                }
                rt += tens[nums / 10 - 2];
                nums %= 10;
            }
            
            if (nums >= 1) {
                if (rt != "") rt += " ";
                rt += ones[nums - 1];
            }
            
            return rt + end;
        }
    
    
        string numberToWords(int num) {
            if (num == 0) return "Zero";
            vector<string> ones = {"One","Two","Three","Four","Five","Six","Seven","Eight","Nine"};
            vector<string> oneTens = {"Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"};
            vector<string> tens = {"Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"};
            vector<string> ends = {" Billion"," Million"," Thousand",""};
            
            string rt = "";
            int temp = 0, endI = 0,bill = 1000000000;
            while (num > 0) {
                if (num / bill > 0) {
                    if (rt != "") rt += " ";
                    rt += translate(ones,oneTens,tens,ends,num / bill,ends[endI]);
                }
                num %= bill;
                bill /= 1000;
                endI++;
            }
            return rt;
        }
    };
    

    In Java
    注意空格
    class Solution {
        private String[] units = {""," Thousand"," Million"," Billion"};
        private String[] singleDigits = {"One","Two","Three","Four","Five","Six","Seven","Eight","Nine"};
        private String[] doubleDigitsTenth = {"Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"};
        private String[] doubleDigits = {"Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"};
        
        public String numberToWords(int num) {
            if (num == 0) return "Zero";
            String rt = "";
            for (int i = 0; i < 4; i++) {
                String cur = toWords((num % 1000), units[i]);
                if (!rt.isEmpty() && !cur.isEmpty()) rt = " " + rt;
                rt = cur + rt;
                num /= 1000; 
            }
            
            return rt;
        }
        
        private String toWords(int num, String unit) {
            String s = "";
            if (num == 0) return s;
            
            if (num >= 100) {
                s += singleDigits[num / 100 - 1] + " Hundred";
                num %= 100;
            }
            if (num > 9 && num < 20) {
                if (!s.isEmpty()) s += " ";
                s += doubleDigitsTenth[num % 10];
            } else {
                if (num > 19) {
                    if (!s.isEmpty()) s += " ";
                    s += doubleDigits[num / 10 - 2];
                    num %= 10;
                }
                if (num != 0) {
                    if (!s.isEmpty()) s += " ";
                    s += singleDigits[num - 1];
                }
            }
            
            return s + unit;
        }
    }
    

    Monday, August 31, 2015

    GeeksforGeeks: Dynamic Programming | Set 28 (Minimum insertions to form a palindrome)

    Minimum insertions to form a palindrome
    ref: http://www.geeksforgeeks.org/dynamic-programming-set-28-minimum-insertions-to-form-a-palindrome/
    假设有minInsert(int begin, int end), s为string,返回 s[begin : end]所需的最少insertion
    如果s[begin] == s[end], minInsert(begin, end) = minInsert(begin + 1, end - 1);
    如果s[begin] != s[end], minInsert(begin, end) = min(minInsert(begin + 1, end), minInsert(begin, end - 1)) + 1;

    以下是递归解法:
    int minInsert(string s, int begin, int end) {
        if (begin == end) return 0;
        if (begin == end - 1) return (s[begin] == s[end])? 0 : 1;
        if (s[begin] == s[end]) {
            return minInsert(s,begin + 1,end - 1);
        }
        return 1 + min(minInsert(s,begin + 1,end),minInsert(s,begin,end - 1));
    }
    

    显而易见,有重复的子问题,所以可以用dp来解决
    int minInsert(string s) {
        int n = s.length();
        vector<vector<int>> dp(n,vector<int>(n,0));
        for (int gap = 1; gap < n; gap++) {
            for (int begin = 0, end = gap; end < n; begin++,end++) {
                if (s[begin] == s[end]) {
                    dp[begin][end] = dp[begin + 1][end - 1];    
                }else {
                    dp[begin][end] = min(dp[begin + 1][end],dp[begin][end - 1]) + 1;    
                }
            }
        }
        
        return dp[0][n - 1];
    }
    

    Thursday, July 2, 2015

    Day 114, Lintcode, #395, Coins in a Line II

    Coins in a Line II
    There are n coins with different value in a line. Two players take turns to take one or two coins from left side until there are no more coins left. The player who take the coins with the most value wins.
    Could you please decide the first player will win or lose?
    -----------------------------------------------------
    方法一
    coins表示在i点的最大利益
    getTwo表示在i点最大利益是否要取2个coin
    class Solution {
    public:
        /**
         * @param values: a vector of integers
         * @return: a boolean which equals to true if the first player will win
         */
        bool firstWillWin(vector<int> &values) {
            // write your code here
            int m = values.size();
            if (m < 3) return true;
            
            vector<int> coins(m + 2,0);
            vector<bool> getTwo(m,true);
            
            coins[m - 1] = values[m - 1];
            coins[m - 2] = values[m - 1] + values[m - 2];
            
            for (int i = m - 3; i >= 0; i--) {
                int takeOne = 0, takeTwo = 0;
                // take one
                if (getTwo[i + 1]) {
                    takeOne = coins[i + 3] + values[i];
                }else {
                    takeOne = coins[i + 2] + values[i];
                }
                
                // take two
                if(getTwo[i + 2]) {
                    takeTwo = coins[i + 4] + values[i] + values[i + 1];
                }else {
                    takeTwo = coins[i + 3] + values[i] + values[i + 1];
                }
                
                coins[i] = max(takeOne,takeTwo);
                if (takeOne > takeTwo) {
                    getTwo[i] = false;
                }
            }
            
            if (getTwo[0]) {
                return coins[0] > coins[2];
            }
            return coins[0] > coins[1];
        }
    };
    
    
    方法二 http://techinpad.blogspot.com/2015/05/lintcode-coins-in-line-ii.html
    方法三 http://www.meetqun.com/thread-9798-1-1.html

    Tuesday, June 23, 2015

    Day 111, ##, Contains Duplicate II, Contains Duplicate III, Maximal Square

    Contains Duplicate II
    Given an array of integers and an integer k, find out whether there there are two distinct indices i and j in the array such that nums[i] = nums[j] and the difference between iand j is at most k. ------------------------------------------------
    this is one of the onsite interview questiona at fb, and I failed
    class Solution {
    public:
        bool containsNearbyDuplicate(vector<int>& nums, int k) {
            unordered_map<int,int> dic;
            for (int i = 0; i < nums.size(); i++) {
                if (dic.find(nums[i]) != dic.end()) {
                    return true;
                }
                dic[nums[i]] = i;
                
                // save space
                if (i - k >= 0) {
                    dic.erase(nums[i - k]);
                }
            }
            return false;
        }
    };
    
    Contains Duplicate III
    Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.
    ------------------------------------------------------------
    方法1,bucket sort,O(n),如果每个bucket里出现2个元素,则可直接返回true。所以确保了在程序运行过程中每个bucket只可能存在1个或者0个元素
    casting的问题
    k < 1 或 t < 0 直接返回false

    (long long)t + 1, + 1是为了防止当t 为0
    class Solution {
    public:
        bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
            if (k <= 0 || t < 0) return false;
            unordered_map<long long,int> bucket;
            
            for (int i = 0; i < nums.size(); i++) {
                long long inter = nums[i] + 2147483648;
                long long curBucket = inter / ((long long)t + 1);
                if (bucket.find(curBucket) != bucket.end() 
                    || (bucket.find(curBucket - 1) != bucket.end() && abs((long long)nums[i] - bucket[curBucket - 1]) <= t)
                    || (bucket.find(curBucket + 1) != bucket.end() && abs((long long)nums[i] - bucket[curBucket + 1]) <= t)) {
                    return true;
                }
                
                bucket[curBucket] = (long long)nums[i];
                if (i - k >= 0) {
                    long long oldBucket = (nums[i - k] + 2147483648) / ((long long)t + 1);
                    bucket.erase(oldBucket);
                }
            }
            
            return false;
        }
    };
    

    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.
    -------------------------------------------------------------
    看了提示tag
    O(m * n) 空间, dp[i][j] 代表以i,j为右下角的正方形边长
    class Solution {
    public:
        int maximalSquare(vector<vector<char>>& matrix) {
            int m = matrix.size();
            if (m == 0) return 0;
            int n = matrix[0].size();
            vector<vector<int> > dp(m,vector<int>(n,0));
            int maxSquare = 0;
            
            for (int i = 0; i < m; i++) {
                if (matrix[i][0] == '1') {
                    dp[i][0] = 1;
                    maxSquare = 1;
                }
            }
            for (int i = 0; i < n; i++) {
                if (matrix[0][i] == '1') {
                    dp[0][i] = 1;
                    maxSquare = 1;
                }
            }
            
            
            for (int i = 1; i < m; i++) {
                for (int j = 1; j < n; j++) {
                    if (matrix[i][j] == '1') {
                        dp[i][j] = 1 + min(dp[i - 1][j - 1],min(dp[i - 1][j],dp[i][j - 1]));
                        maxSquare = max(maxSquare,dp[i][j]);
                    }
                }
            }
            
            return maxSquare * maxSquare;
        }
    };
    

    O(n)空间优化,注意 else 语句将 dp[j] 清0
    class Solution {
    public:
        int maximalSquare(vector<vector<char>>& matrix) {
            int m = matrix.size();
            if (m == 0) return 0;
            int n = matrix[0].size();
            vector<int> dp(n + 1, 0);
            int maxSquare = 0, pre = 0;
    
            for (int i = 0; i < m; i++) {
                for (int j = 1; j < n + 1; j++) {
                    int temp = dp[j];
                    if (matrix[i][j - 1] == '1') {
                        dp[j] = 1 + min(dp[j - 1],min(pre,dp[j]));
                        maxSquare = max(maxSquare,dp[j]);
                    }else {
                        dp[j] = 0;
                    }
                    
                    pre = temp;
                }
            }
            
            return maxSquare * maxSquare;
        }
    };
    

    Tuesday, June 16, 2015

    Day 108, ##,Add and Search Word - Data structure design, House Robber II, Shortest Palindrome

    Add and Search Word - Data structure design
    Design a data structure that supports the following two operations:
    void addWord(word)
    bool search(word)
    
    search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.
    For example:
    addWord("bad")
    addWord("dad")
    addWord("mad")
    search("pad") -> false
    search("bad") -> true
    search(".ad") -> true
    search("b..") -> true
    
    Note:
    You may assume that all words are consist of lowercase letters a-z.
    --------------------------------------------------------------
    Trie,
    class TrieNode {
    public:
        vector<TrieNode *> children;
        bool end;
        TrieNode() {
            end = false;
            children = vector<TrieNode *>(26,NULL);
        }
    };
    
    class WordDictionary {
    public:
        WordDictionary() {
            root = new TrieNode();
        }
        
        // Adds a word into the data structure.
        void addWord(string word) {
            TrieNode *itr = root;
            for (int i = 0; i < word.length(); i++) {
                if (itr->children[word[i] - 'a'] == NULL) {
                    itr->children[word[i] - 'a'] = new TrieNode();
                }
                itr = itr->children[word[i] - 'a'];
            }
            itr->end = true;
        }
    
        bool searchHelper(string word, int index,TrieNode *itr) {
            if (index == word.length()) return itr->end;
            if (word[index] != '.') {
                TrieNode* t = itr->children[word[index] - 'a']; 
                if (t != NULL) {
                    return searchHelper(word,index + 1, t);
                }
                return false;
            }
            
            for (int i = 0; i < 26; i++) {
                TrieNode* t = itr->children[i]; 
                if (t != NULL && searchHelper(word,index + 1, t)) {
                    return true;
                }
            }
            
            return false;
        }
    
        // Returns if the word is in the data structure. A word could
        // contain the dot character '.' to represent any one letter.
        bool search(string word) {
            return searchHelper(word,0,root);
        }
    private:
        TrieNode* root;
    };
    
    // Your WordDictionary object will be instantiated and called as such:
    // WordDictionary wordDictionary;
    // wordDictionary.addWord("word");
    // wordDictionary.search("pattern");
    
    

    Java, addWord可以用for循环,也可以递归。searchWord的时候只能递归了,因为遇到‘.’得尝试所有26位,然后backtrace
    class WordDictionary {
        
        private Node root;
    
        /** Initialize your data structure here. */
        public WordDictionary() {
            root = new Node('0');
        }
        
        /** Adds a word into the data structure. */
        public void addWord(String word) {
            
            Node itr = root;
            for (int i = 0; i < word.length(); i++) {
                char c = word.charAt(i);
                if (!itr.letters.containsKey(c)){
                    itr.letters.put(c, new Node(c));
                }
                
                if (i == word.length() - 1) {
                    itr.letters.get(c).isWord = true;
                }
                
                itr = itr.letters.get(c);
            }
            
        }
        
        /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
        public boolean search(String word) {
            
            return helper(word, 0, root);
        }
        
        private boolean helper(String word, int index, Node node) {
            
            if (index == word.length()) {
                return node.isWord;
            }
            
            char c = word.charAt(index);
            if (node.letters.containsKey(c)) {
                if (helper(word, index + 1, node.letters.get(c))) return true;
            }else if (c == '.') {
                for (Map.Entry entry : node.letters.entrySet()) {
                    if (helper(word, index + 1, entry.getValue())) {
                        return true;
                    }
                }
            }
            
            return false;
            
        }
    }
    
    class Node{
        public char c;
        public Map letters;
        public boolean isWord;
        
        public Node(char c) {
            this.c = c;
            letters = new HashMap();
            isWord = false;
        }
    }
    
    /**
     * Your WordDictionary object will be instantiated and called as such:
     * WordDictionary obj = new WordDictionary();
     * obj.addWord(word);
     * boolean param_2 = obj.search(word);
     */
    
    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.
    ----------------------------------------------------
    Used prefix tree from the previous question
    class TrieNode {
    public:
        TrieNode() {
            next = vector<TrieNode*>(26,NULL);
            terminal = false;
        }
     
        char value;
        vector<TrieNode*> next;
        bool terminal;
    };
    
    class Trie {
    public:
        Trie() {
            root = new TrieNode();
        }
     
        // Inserts a word into the trie.
        void insert(string s) {
            TrieNode *cur = root;
            for (int i = 0; i < s.length(); i++) {
                char c = s[i] - 'a';
                if (cur->next[c] == NULL) {
                    TrieNode *trie = new TrieNode();
                    trie->value = c;
                    cur->next[c] = trie;
                }
                cur = cur->next[c];
            }
            cur->terminal = true;
        }
     
        // Returns if the word is in the trie.
        bool search(string key) {
            TrieNode *cur = root;
            for (int i = 0; i < key.length(); i++) {
                char c = key[i] - 'a';
                if (cur->next[c] == NULL) {
                    return false;
                }
                 
                cur = cur->next[c];
            }
             
            return cur->terminal;
        }
     
        // Returns if there is any word in the trie
        // that starts with the given prefix.
        bool startsWith(string prefix) {
            TrieNode *cur = root;
            for (int i = 0; i < prefix.length(); i++) {
                char c = prefix[i] - 'a';
                if (cur->next[c] == NULL) {
                    return false;
                }
                 
                cur = cur->next[c];
            }
             
            return true;
        }
    private:
        TrieNode* root;
    };
    
    class Solution {
    public:
        void search(vector<string> &rt, vector<vector<char>>& board, 
                vector<vector<bool> > &visit, Trie &trie, string word, int row, int col, unordered_set<string> &hadIt) {
            if (row < 0 || row >= board.size() || col < 0 || col >= board[0].size() || visit[row][col]) {
                return;
            }
            word += board[row][col];
            visit[row][col] = true;
            if (hadIt.find(word) == hadIt.end() && trie.search(word)) {
                hadIt.insert(word);
                rt.push_back(word);
            }
            
            if (trie.startsWith(word)) {
                search(rt,board,visit,trie,word,row + 1,col,hadIt);
                search(rt,board,visit,trie,word,row - 1,col,hadIt);
                search(rt,board,visit,trie,word,row,col + 1,hadIt);
                search(rt,board,visit,trie,word,row,col - 1,hadIt);
            }
            visit[row][col] = false;
        }
    
        vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
            Trie trie;
            for (int i = 0; i < words.size(); i++) {
                trie.insert(words[i]);
            }
            
            vector<string> rt;
            vector<vector<bool> > visit(board.size(),vector<bool>(board[0].size(),false));
            unordered_set<string> hadIt;
            for (int i = 0; i < board.size(); i++) {
                for (int j = 0; j <board[0].size(); j++) {
                    search(rt,board,visit,trie,"",i,j,hadIt);
                }
            }
            
            return rt;
        }
    };
    

    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 are arranged 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.
    ----------------------------------------------
    看了答案!
    class Solution {
    public:
        int robHelper(vector<int>& nums, int left, int right) {
            int pre_1 = 0, pre_2 = 0, pre_3 = 0;
            for (int i = left; i <= right; i++) {
                int temp = pre_3;
                pre_3 = max(pre_3,max(pre_1,pre_2) + nums[i]);
                pre_1 = pre_2;
                pre_2 = temp;
            }
            
            return pre_3;
        }
    
        int rob(vector<int>& nums) {
            if (nums.size() == 0) return 0;
            if (nums.size() == 1) return nums[0];
            return max(robHelper(nums,0,nums.size() - 2),robHelper(nums,1,nums.size() - 1));
        }
    };
    

    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".
    ---------------------------------------------------------------
    O(n^2) 找prefix是palindrome。超时
    class Solution {
    public:
        bool isPalindrome(string s) {
            for (int i = 0; i < s.length() / 2; i++) {
                if (s[i] != s[s.length() - 1 - i]) return false;
            }
            
            return true;
        }
        
        int longestPal(string s) {
            for (int i = s.length(); i > 0; i--) {
                if (isPalindrome(s.substr(0,i))) {
                    return i;
                }
            }
            
            return 0;
        }
        
        string shortestPalindrome(string s) {
            int length = longestPal(s);
            string copy = s;
            for (int i = 0; i < copy.length() - length; i++) {
                s = copy[length + i] + s;    
            }
            
            return s;
        }
    };
    
    看了答案!对KMP要灵活运用
    s + special char + reverse(s)
    然后运用KMP的failure function计算出s的prefix和revsers(s)的suffix相等的最长长度
    ref: https://leetcode.com/discuss/36807/c-8-ms-kmp-based-o-n-time-%26-o-n-memory-solution
    class Solution {
    public:
        vector<int> computePrefixTable(string pattern) {
            int m = pattern.length();
            vector<int> table(m,0);
            int matchedLength = 0;
            
            for (int i = 1; i < m; i++) {
                // until find the next char at matchedLength is equal to char at i
                // or matchedLength is zero
                while (matchedLength > 0 && pattern[matchedLength] != pattern[i]) {
                    matchedLength = table[matchedLength - 1];
                }
                if (pattern[matchedLength] == pattern[i]) {
                    matchedLength++;
                }
                table[i] = matchedLength;
            }
            
            return table;
        }
        string shortestPalindrome(string s) {
            string rev = s;
            reverse(rev.begin(),rev.end());
            string pattern = s + "*" + rev;
            vector<int> table = computePrefixTable(pattern);
            
            return rev.substr(0,rev.length() - table[table.size() - 1]) + s;
        }
    };