LeetCode 127 - Word Ladder I


LeetCode – Word Ladder
Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:
  • Only one letter can be changed at a time
  • Each intermediate word must exist in the dictionary
For example, given start = "hit", end = "cog", dict = ["hot","dot","dog","lot","log"], as one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", return its length 5.
Note:
  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
Key Point: BFS, We don't create the edit-distance graph first, instead we check every possible string exists in the dictionary.

There is an edge between two vertices, if and only if they differ by exactly one character. Now we are asked to find the length of the shortest path from start to end, which is readily solved by breadth-first search.
We can build the graph in init step, or on the fly.
Another way is to try all the strings that are different from the current string by one character. Since the characters are lowercase, the number of such strings is 25n , which is acceptable.
X.  Two-end BFS
https://discuss.leetcode.com/topic/29303/two-end-bfs-in-java-31ms
public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
 Set<String> beginSet = new HashSet<String>(), endSet = new HashSet<String>();

 int len = 1;
 int strLen = beginWord.length();
 HashSet<String> visited = new HashSet<String>();
 
 beginSet.add(beginWord);
 endSet.add(endWord);
 while (!beginSet.isEmpty() && !endSet.isEmpty()) {
  if (beginSet.size() > endSet.size()) {
   Set<String> set = beginSet;
   beginSet = endSet;
   endSet = set;
  }

  Set<String> temp = new HashSet<String>();
  for (String word : beginSet) {
   char[] chs = word.toCharArray();

   for (int i = 0; i < chs.length; i++) {
    for (char c = 'a'; c <= 'z'; c++) {
     char old = chs[i];
     chs[i] = c;
     String target = String.valueOf(chs);

     if (endSet.contains(target)) {
      return len + 1;
     }

     if (!visited.contains(target) && wordList.contains(target)) {
      temp.add(target);
      visited.add(target);
     }
     chs[i] = old;
    }
   }
  }

  beginSet = temp;
  len++;
 }
 
 return 0;
}

X. BFS
public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
    wordList.add(endWord);
    Queue<String> queue = new LinkedList<String>();
    queue.add(beginWord);
    int level = 0;
    while(!queue.isEmpty()){
        int size = queue.size();
        for(int i = 0; i < size; i++){
            String cur = queue.remove();
            if(cur.equals(endWord)){ return level + 1;}
            for(int j = 0; j < cur.length(); j++){
                char[] word = cur.toCharArray();
                for(char ch = 'a'; ch < 'z'; ch++){
                    word[j] = ch;
                    String check = new String(word);
                    if(!check.equals(cur) && wordList.contains(check)){
                        queue.add(check);
                        wordList.remove(check);
                    }
                }
            }
        }
        level++;
    }
    return 0;
}
Also check the code at http://codingrecipies.blogspot.com/2014/06/word-chain.html
https://linchicoding.wordpress.com/2014/10/13/leetcode-word-ladder/

    public int ladderLength(String start, String end, Set<String> dict) {
        if (start == null || end == null || start.length() != end.length() || start.length() == 0)
            return 0;
        // A queue used for breadth-first search
        Deque<String> queue = new ArrayDeque<String>();
        queue.offer(start);
        Set<String> visited = new HashSet<String>();    // Record the strings that have been visited
        int depth = 1;
        int nodesInCurrentLevel = 1, nodesInNextLevel = 0;
        // A breadth-first search starting from "start"
        while (queue.peek() != null) {
            String current = queue.poll();
            nodesInCurrentLevel--;
            // Try each string that is one character away from the current one
            for (int i = 0; i < current.length(); i++) {
                char[] charCurrent = current.toCharArray();
                for (char c = 'a'; c <= 'z'; c++) {
                    charCurrent[i] = c;
                    String temp = new String(charCurrent);
                    if (temp.equals(end))   // Reach target string with one more transformation
                        return depth+1;
                    if (!visited.contains(temp) && dict.contains(temp)) {
                        queue.offer(temp);
                        nodesInNextLevel++;
                        visited.add(temp);
                    }
                }
            }

            // All nodes at the current level are done; prepare to go to the next level
            if (nodesInCurrentLevel == 0) {
                nodesInCurrentLevel = nodesInNextLevel;
                nodesInNextLevel = 0;
                depth++;
            }
        }
        return 0;
    }
EPI Java SOlution: Transform one string to another
TransformStringToOther.java
  public static int transformString(Set<String> D, String s, String t) {
    LinkedList<Pair<String, Integer>> q = new LinkedList<>();
    D.remove(s); // Marks s as visited by erasing it in D.
    q.push(new Pair<>(s, 0));

    while (!q.isEmpty()) {
      Pair<String, Integer> f = q.peek();
      // Returns if we find a match.
      if (f.getFirst().equals(t)) {
        return f.getSecond(); // Number of steps reaches t.
      }

      // Tries all possible transformations of f.first.
      String str = f.getFirst();
      for (int i = 0; i < str.length(); ++i) {
        String strStart = i == 0 ? "" : str.substring(0, i);
        String strEnd = i + 1 < str.length() ? str.substring(i + 1) : "";
        for (int j = 0; j < 26; ++j) { // Iterates through 'a' ~ 'z'.
          String modStr = strStart + (char) ('a' + j) + strEnd;
          if (D.remove(modStr)) {
            q.push(new Pair<>(modStr, f.getSecond() + 1));
          }
        }
      }
      q.pop();
    }

    return -1; // Cannot find a possible transformations.
  }
LeetCode – Word Ladder
https://leetcode.com/discuss/30872/short-java-bfs-solution
I modify the part of string concatenation and it runs with 476 ms
We can use two queues to traverse the tree, one stores the nodes, the other stores the step numbers.
    public int ladderLength(String start, String end, HashSet<String> dict) {
 
        if (dict.size() == 0)  
            return 0; 
 
        LinkedList<String> wordQueue = new LinkedList<String>();
        LinkedList<Integer> distanceQueue = new LinkedList<Integer>();
 
        wordQueue.add(start);
        distanceQueue.add(1);
 
 
        while(!wordQueue.isEmpty()){
            String currWord = wordQueue.pop();
            Integer currDistance = distanceQueue.pop();
 
            if(currWord.equals(end)){
                return currDistance;
            }
 
            for(int i=0; i<currWord.length(); i++){
                char[] currCharArr = currWord.toCharArray();
                for(char c='a'; c<='z'; c++){
                    currCharArr[i] = c;
                    String newWord = new String(currCharArr);
                    if(dict.contains(newWord)){
                        wordQueue.add(newWord);
                        distanceQueue.add(currDistance+1);
                        dict.remove(newWord);
                    }
                }
            }
        }
 
        return 0;
    }
https://leetcode.com/discuss/50930/java-solution-using-dijkstras-algorithm-with-explanation
public int ladderLength(String beginWord, String endWord, Set<String> wordDict) { Set<String> reached = new HashSet<String>(); reached.add(beginWord); wordDict.add(endWord); int distance = 1; while(!reached.contains(endWord)) { Set<String> toAdd = new HashSet<String>(); for(String each : reached) { for (int i = 0; i < each.length(); i++) { char[] chars = each.toCharArray(); for (char ch = 'a'; ch <= 'z'; ch++) { chars[i] = ch; String word = new String(chars); if(wordDict.contains(word)) { toAdd.add(word); wordDict.remove(word); } } } } distance ++; if(toAdd.size() == 0) return 0; reached = toAdd; } return distance; }
https://linchicoding.wordpress.com/2014/10/13/leetcode-word-ladder/
  1. At first I was considering using recursion, which results in a “DFS” structure, and need to keep track of min steps, because it may already traverse down too far in one recursion then reach the end, yet in other branches may only need much fewer steps. This is an indication that we should use “BFS” instead.
https://discuss.leetcode.com/topic/20965/java-solution-using-dijkstra-s-algorithm-with-explanation
ublic int ladderLength(String beginWord, String endWord, Set<String> wordDict) {
    Set<String> reached = new HashSet<String>();
    reached.add(beginWord);
    wordDict.add(endWord);
 int distance = 1;
 while(!reached.contains(endWord)) {
  Set<String> toAdd = new HashSet<String>();
  for(String each : reached) {
   for (int i = 0; i < each.length(); i++) {
                char[] chars = each.toCharArray();
                for (char ch = 'a'; ch <= 'z'; ch++) {
                 chars[i] = ch;
                    String word = new String(chars);
                    if(wordDict.contains(word)) {
                     toAdd.add(word);
                     wordDict.remove(word);
                    }
                }
   }
  }
  distance ++;
  if(toAdd.size() == 0) return 0;
  reached = toAdd;
 }
 return distance;
}
Basically I keep two sets of words, one set reached that represents the borders that have been reached with "distance" steps; another set wordDict that has not been reached. In the while loop, for each word in the reached set, I give all variations and check if it matches anything from wordDict, if it has a match, I add that word into toAdd set, which will be my "reached" set in the next loop, and remove the word from wordDict because I already reached it in this step. And at the end of while loop, I check the size of toAdd, which means that if I can't reach any new String from wordDict, I won't be able to reach the endWord, then just return 0. Finally if the endWord is in reached set, I return the current steps "distance".
The idea is that reached always contain only the ones we just reached in the last step, and wordDict always contain the ones that haven't been reached. This is pretty much what Dijkstra's algorithm does, or you can see this as some variation of BFS.

X. Two-End BFS
https://discuss.leetcode.com/topic/10372/share-my-two-end-bfs-in-c-80ms/9
https://leetcode.com/discuss/68935/two-end-bfs-in-java-31ms
Convert this problem to a math problem: Find a shortest path from one Vertex to another in a graph. Then searching from both Vertexes always visits less Vertexes than searching from one Vertex. But I can't prove this theory

using two ends by alternating beginSet and endSet
you are replacing a big search tree in the one-end solution with two smaller trees in the two-end solution. Both solutions have the same TOTAL depth, yet tree width grows exponentially w.r.t. depths, and the two-end solutions results in less nodes being visited.

Though simply remove target from wordList will be more efficient, but will modify original parameters. So I suggest using this HashSet to keep all visited is more suitable.

i think the intuition is that you are replacing a big search tree in the one-end solution with two smaller trees in the two-end solution. Both solutions have the same TOTAL depth, yet tree width grows exponentially w.r.t. depths, and the two-end solutions results in less nodes being visited.

public int ladderLength(String beginWord, String endWord, Set<String> wordList) { Set<String> beginSet = new HashSet<String>(), endSet = new HashSet<String>(); int len = 1; int strLen = beginWord.length(); HashSet<String> visited = new HashSet<String>(); beginSet.add(beginWord); endSet.add(endWord); while (!beginSet.isEmpty() && !endSet.isEmpty()) { if (beginSet.size() > endSet.size()) { Set<String> set = beginSet; beginSet = endSet; endSet = set; } Set<String> temp = new HashSet<String>(); for (String word : beginSet) { char[] chs = word.toCharArray(); for (int i = 0; i < chs.length; i++) { for (char c = 'a'; c <= 'z'; c++) { char old = chs[i];// chs[i] = c;// String target = String.valueOf(chs); if (endSet.contains(target)) { return len + 1; } if (!visited.contains(target) && wordList.contains(target)) { temp.add(target); visited.add(target); } chs[i] = old;//\\ } } } beginSet = temp; len++; } return 0; }

This is my code with some small modifications. Run time is 23ms.
public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
    int pathLength = 2;
    
    Set<String> start = new HashSet<>();
    Set<String> end = new HashSet<>();
    start.add(beginWord);
    end.add(endWord);
    wordList.remove(beginWord);
    wordList.remove(endWord);
    
    while(!start.isEmpty()){
        if(start.size() > end.size()){
            Set<String> temp = start;
            start = end;
            end = temp;
        }
        Set<String> next = new HashSet<>();
        for(String cur : start){
            char[] strArray = cur.toCharArray();
            for(int i = 0; i < strArray.length;i++){
                char old = strArray[i];
                for(char c = 'a';c <= 'z';c++){
                    strArray[i] = c;
                    String str = String.valueOf(strArray);
                    if(end.contains(str)){
                        return pathLength;
                    }
                    if(wordList.contains(str)){
                        next.add(str);
                        wordList.remove(str);
                    }
                }
                strArray[i] = old;
            }
        }
        start = next;
        pathLength++;
    }
    return 0;
    
}
https://leetcode.com/discuss/44079/super-fast-java-solution-using-two-end-bfs
Two further improvements.
  1. for (String word : set1) { dict.remove(word); }; can be replace by dict.removeAll(set1)
  2. char[] chars = str.toCharArray(); put it outside of second for loop can be faster(also need to record the original char and recover), since Java uses System.arraycopy to implement str.toCharArray() method. This can be N times faster. N is the length of word.
public int ladderLength(String start, String end, Set<String> dict) { Set<String> set1 = new HashSet<String>(); Set<String> set2 = new HashSet<String>(); set1.add(start); set2.add(end); return helper(dict, set1, set2, 1); } int helper(Set<String> dict, Set<String> set1, Set<String> set2, int level) { if (set1.isEmpty()) return 0; if (set1.size() > set2.size()) return helper(dict, set2, set1, level); // remove words from both ends for (String word : set1) { dict.remove(word); }; for (String word : set2) { dict.remove(word); }; // the set for next level Set<String> set = new HashSet<String>(); // for each string in the current level for (String str : set1) { for (int i = 0; i < str.length(); i++) { char[] chars = str.toCharArray(); // change letter at every position for (char ch = 'a'; ch <= 'z'; ch++) { chars[i] = ch; String word = new String(chars); // found the word in other end(set) if (set2.contains(word)) { return level + 1; } // if not, add to the next level if (dict.contains(word)) { set.add(word); } } } } return helper(dict, set2, set, level + 1); }
Two-End BFS recusion
https://discuss.leetcode.com/topic/17956/super-fast-java-solution-using-two-end-bfs
    public int ladderLength(String start, String end, Set<String> dict) {
        Set<String> set1 = new HashSet<String>();
        Set<String> set2 = new HashSet<String>();
        
        set1.add(start);
        set2.add(end);
        
        return helper(dict, set1, set2, 1);
    }
    
    int helper(Set<String> dict, Set<String> set1, Set<String> set2, int level) {
        if (set1.isEmpty()) return 0;
        
        if (set1.size() > set2.size()) return helper(dict, set2, set1, level);
        
        // remove words from both ends
        for (String word : set1) { dict.remove(word); };
        for (String word : set2) { dict.remove(word); };
        
        // the set for next level
        Set<String> set = new HashSet<String>();
        
        // for each string in the current level
        for (String str : set1) {
            for (int i = 0; i < str.length(); i++) {
                char[] chars = str.toCharArray();
                
                // change letter at every position
                for (char ch = 'a'; ch <= 'z'; ch++) {
                    chars[i] = ch;
                    String word = new String(chars);
                    
                    // found the word in other end(set)
                    if (set2.contains(word)) {
                        return level + 1;
                    }
                    
                    // if not, add to the next level
                    if (dict.contains(word)) {
                        set.add(word);
                    }
                }
            }
        }
        
        return helper(dict, set2, set, level + 1);
    }
http://dp2.me/blog/?p=863
前几天和群友说起来,构图的时候,除去将每个字符依次从a替换至z,有没有进一步的优化。

当然是有……例如我有cap这个单词,创建三个key,*ap, c*p, ca*,然后将cap加入这三个key对应的list。依次对字典里所有单词做相同的事情。

两个不同的单词不可能同时分别出现在两个list中,(比如说单词A,单词B出现在 *ap中,单词A出现在c*p中,则单词B不可能出现在c*p中)。于是对于某个单词,比如说cap,只要连接*ap, c*p, ca*三个list,就可以得到它在图中所有的邻接节点
经验证速度比我的用a-z替换的code快一倍。当然,再进一步优化可以加上双向广搜。

X.
https://leetcode.com/discuss/433/keep-hitting-time-limit-exceeded-exception-word-ladder-java
Seems you use O(N^2) to build the graph, then find to shortest path from start string toend string. It is a solution, but not efficient.
You can do the BFS in this way, initialize the BFS queue with only one element start string. Then go thru the BFS queue one by one, as we know the queue will increase during the BFS process. The way to expand the current string to see if it can generate another string in the dictionary and not appear in the BFS queue before. How to generate? Scan the characters in the string one by one, try to replace with other characters a to z.
If you do BFS in the way above, you do not have to touch all words in the dictionary to build graph. Considering the dictionary might be huge
public int ladderLength(String start, String end, HashSet<String> dict) { //building a graph dict.add(start); dict.add(end); int n = dict.size(); //the graph consisting nodes array Node[] nodes= new Node[n]; Iterator itr = dict.iterator(); Node startNode=null, endNode=null; //create node for each dict word for (int i = 0; i < n; i++) { Node nd = new Node(); nd.data = (String)itr.next(); nodes[i] = nd; //set start and end if(nd.data.equals(start)) startNode = nd; if(nd.data.equals(end)) endNode = nd; } //O(n-square) //find neighbors of each node for (int i = 0; i < n; i++) { Node current = nodes[i]; current.neighbor = neighbor(current,nodes); } //BFS implemented by a Queue Queue<Node> aQ = new LinkedList<Node>(); aQ.add(startNode); int counter = 1; while(!aQ.isEmpty()){ //O(n-square) n is the # of edge Node pointer = (Node)aQ.poll(); mark(pointer); if(pointer==endNode){ return pointer.distance; } Iterator<Node> neiItr = pointer.neighbor.iterator(); while (neiItr.hasNext()) { Node current = (Node)neiItr.next(); if(current.visited==false){ aQ.add(current); current.distance = ++counter; } } } return 0; } public void mark(Node t){ t.visited=true; } public void markAll(ArrayList<Node> t){ Iterator itr = t.iterator(); while(itr.hasNext()){ ((Node)itr.next()).visited=true; } } public ArrayList<Node> neighbor(Node nd, Node[] nodes){ ArrayList<Node> neighors = new ArrayList<Node>(); for (int i = 0; i < nodes.length; i++) { Node current = nodes[i]; if(current.isNeighborOf(nd)) neighors.add(current); } return neighors; } class Node{ String data; int distance = 0; boolean visited = false; ArrayList<Node> neighbor; /** * O(n) * @param t * @return */ public boolean isNeighborOf(Node t){ int ctr = 0; for (int i = 0; i < data.length(); i++) { if(data.charAt(i)!=t.data.charAt(i)){ ctr++; if(ctr>1) return false; } } //ctr has to be bigger than 1 //set is non duplicate return true; } }
X. Dijkstra
https://leetcode.com/discuss/20587/accepted-java-solution-based-on-dijkstras-algorithm
why you like to use Dijkstra in an unweighted graph?
if weight is 1, you can just use breadth first search.
public int ladderLength(String start, String end, Set<String> dict) { // Init vertices WordVertex startVertex = new WordVertex(start); WordVertex endVertex = new WordVertex(end); startVertex.dist = 0; List<WordVertex> vertices = new ArrayList<WordVertex>(); vertices.add(startVertex); vertices.add(endVertex); for (String word:dict) { vertices.add(new WordVertex(word)); } // Construct graph for(int i=0; i<vertices.size(); i++) { WordVertex vertex = vertices.get(i); for(int j=i+1; j<vertices.size(); j++) { WordVertex neighbor = vertices.get(j); int diff = 0; for (int k=0; k<vertex.word.length(); k++) { if (vertex.word.charAt(k) != neighbor.word.charAt(k) && diff++ == 1) { break; } } if (diff == 1) { vertex.neighbors.add(neighbor); neighbor.neighbors.add(vertex); } } } // Find shortest path. Dijkstra's algorithm. PriorityQueue<WordVertex> queue = new PriorityQueue<WordVertex>(); for (WordVertex v:vertices) { queue.add(v); } while(!queue.isEmpty()) { WordVertex v = queue.poll(); if (v.dist == Integer.MAX_VALUE) continue; for (WordVertex n:v.neighbors) { if (!n.visited) { if (v.dist + 1 < n.dist) { n.dist = v.dist + 1; queue.remove(n); queue.add(n); } } } v.visited = true; } return endVertex.dist == Integer.MAX_VALUE ? 0 : endVertex.dist + 1; }
http://www.geeksforgeeks.org/length-of-shortest-chain-to-reach-a-target-word/
// To check if strings differ by exactly one character
bool isadjacent(string& a, string& b)
{
    int count = 0;  // to store count of differences
    int n = a.length();
    // Iterate through all characters and return false
    // if there are more than one mismatching characters
    for (int i = 0; i < n; i++)
    {
        if (a[i] != b[i]) count++;
        if (count > 1) return false;
    }
    return count == 1 ? true : false;
}
// A queue item to store word and minimum chain length
// to reach the word.
struct QItem
{
    string word;
    int len;
};
// Returns length of shortest chain to reach 'target' from 'start'
// using minimum number of adjacent moves.  D is dictionary
int shortestChainLen(string& start, string& target, set<string> &D)
{
    // Create a queue for BFS and insert 'start' as source vertex
    queue<QItem> Q;
    QItem item = {start, 1};  // Chain length for start word is 1
    Q.push(item);
    // While queue is not empty
    while (!Q.empty())
    {
        // Take the front word
        QItem curr = Q.front();
        Q.pop();
        // Go through all words of dictionary
        for (typeof(D.begin()) it = D.begin(); it != D.end(); it++)
        {
            // Process a dictionary word if it is adjacent to current
            // word (or vertex) of BFS
            string temp = *it;
            if (isadjacent(curr.word, temp))
            {
                // Add the dictionary word to Q
                item.word = temp;
                item.len = curr.len + 1;
                Q.push(item);
                // Remove from dictionary so that this word is not
                // processed again.  This is like marking visited
                D.erase(temp);
                // If we reached target
                if (temp == target)
                  return item.len;
            }
        }
    }
    return 0;
}
Read full article from LeetCode - Word Ladder | Darren's Blog

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts