Longest String Chain


LIKE CODING: MJ [56] Longest String Chain
Given a set of strings, find the longest string chain. Two strings are chained if 
    1. both strings belong to the given set
    2. the second string is generated  by remove one letter in the first string
For example:
Given vector<string> w = {a,ba,bca,bda,bdca}, the longest string chain is bdca->bda->ba->a.

Solution:
Represent the string chain by a Trie like structure. Record the depth while building Trie. 

    bdca 
   |      |
 bda    bca
   |        | 
  ba      ba
   |
   a
https://www.cnblogs.com/EdwardLiu/p/6177843.html
DP use HashMap:
根据string的长度sort,然后维护每个string的longest chain,default为1,如果删除某个char生成的string能提供更长的chain,则更新

 9     public int findLongestChain(String[] words) {
10         if (words==null || words.length==0) return 0;
11         int longestChain = 0;
12         Arrays.sort(words, new Comparator<String>() {
13             public int compare(String str1, String str2) {
14                 return str1.length()-str2.length();
15             }
16         });
17         HashMap<String, Integer> map = new HashMap<String, Integer>();
18         for (String word : words) {
19             if (map.containsKey(word)) continue;
20             map.put(word, 1);
21             for (int i=0; i<word.length(); i++) {
22                 StringBuilder sb = new StringBuilder(word);
23                 sb.deleteCharAt(i);
24                 String after = sb.toString();
25                 if (map.containsKey(after) && map.get(after)+1 > map.get(word)) {
26                     map.put(word, map.get(after)+1);
27                 }
28             }
29             if (map.get(word) > longestChain) longestChain = map.get(word);
30         }
31         return longestChain;
32     }
X. If we don't sort, then we have to dfs
static int longest_chain(String[] w) {
    if (null == w || w.length < 1) {
        return 0;
    }

    int maxChainLen = 0;

    HashSet<String> words = new HashSet<>(Arrays.asList(w));
    HashMap<String, Integer> wordToLongestChain = new HashMap<>();

    for (String word : w) {
        if (maxChainLen > word.length()) {
            continue;
        }
        int curChainLen = find_chain_len(word, words, wordToLongestChain) + 1;
        wordToLongestChain.put(word, curChainLen);
        maxChainLen = Math.max(maxChainLen, curChainLen);
    }
    return maxChainLen;
}

static int find_chain_len(String word, HashSet<String> words,
        HashMap<String, Integer> wordToLongestChain) {
    int curChainLen = 0;

    for (int i = 0; i < word.length(); i++) {
        String nextWord = word.substring(0, i) + word.substring(i + 1);
        if (words.contains(nextWord)) {
            if (wordToLongestChain.containsKey(nextWord)) {
                curChainLen = Math.max(curChainLen, wordToLongestChain.get(nextWord));
            } else {
                int nextWordChainLen = find_chain_len(nextWord, words, wordToLongestChain);
                curChainLen = Math.max(curChainLen, nextWordChainLen + 1);
            }
        }
    }

    return curChainLen;
}

class TrieNode{
public:
    string key;
    int depth = 0;
    unordered_set<TrieNode*> children;
    TrieNode(string k):key(k){};
    TrieNode(){};
};
class LongChain{
public:
    unordered_map<string, TrieNode*> hash;
    unordered_set<string> dictset;
    void extend(TrieNode* root){
        string w = root->key;
        for(int i=0; i<(int)w.size(); ++i){
            string wt = w;
            wt.erase(wt.begin()+i);
            if(dictset.count(wt)){
                if(hash.count(wt)==0){
                    hash[wt] = new TrieNode(wt);
                    extend(hash[wt]);
                }
                root->children.insert(hash[wt]);
            }
        }
    }
    void build(vector<string> dict){
        for(auto w:dict) dictset.insert(w);
        for(auto w:dict){
            if(hash.count(w)==0){
                hash[w] = new TrieNode(w);
                extend(hash[w]);
            }
        }
    }
    int getMaxLen(vector<string> dict){
        build(dict);
        int ret = 0;
        for(auto w:dict){
            ret = max(ret, getMaxLen(hash[w]));
        }
        return ret;
    }
    int getMaxLen(TrieNode *node){
        if(node->depth==0){
            if(node->children.empty()){
                node->depth = 1;
            }else{
                int len = 0;
                for(auto c:node->children){
                    len = max(len, getMaxLen(c));
                }
                node->depth = len+1;
            }
        }
        return node->depth;
    }
    void print(){
        for(auto w:dictset){
            if(hash.count(w)) print(hash[w], "");
        }
    }
    void print(TrieNode *node, string ss){
        string w = node->key;
        cout<<ss<<w<<endl;
        hash.erase(w);
        for(auto n:node->children){
            if(hash.count(n->key)) print(hash[n->key], ss+"----");
        }
    }
};
https://github.com/xieqilu/Qilu-leetcode/blob/master/B218.LongestChain.cs
This problem is very similiar to Word Ladder, the methof is almost the same. We can view
this problem as a tree problem and each word in the input string array can be the root. Starting
from each root, we perform the BFS Level Order traverse, remove each char from root to check all
possible children for next level. And whenver we hit a string that only has one char, we find the
longest chain and return depth. If we never hit a string that only has one char, then we will search
to the deepest level as we can, and return the largest depth.
Solution:
Differences from the solution for Word Ladder:
1, we need to construct a dictionary for all words in input string array to enable quick look-up.
2, each word in the input array can be the root, so we need to traverse the array and try each word
as the root.
3, Use variable res to save current longest length. If a word in the array is shorter than or equal
to res, no need to try BFS on it, because from this word we cannot find a longer length. Or when the
length of the word is 1, dont't do BFS, too.
4, In the Bfs method, we don't need to use the HashSet visited to store all visited words. Because
in this problem the length of a child word must be shorted than its parent, so a child will never
point reversely to its parent, thus we don't need to worry about a cycle. So this problem is excately
a tree problem in which only parent can points to child. The word ladder problem is more like a 
graph problem in which two nodes can point to each other.
5, There are two situations in the Bfs method to return depth:
5.1, we hit a child that has only one char, then we immediately return depth. Because the child belongs to the next level, so return depth+1.
5.2, we got no valid child at a level thus the search is terminated, then we must return depth-1
because we terminate the search at the current empty level, so the chain actually ends at the last
level.
Time complexity: O(n^2)  n is the number of words in input array
Use each word as the root, in each pass, we will at most search for all n words, so O(n^2)
Space: O(n)  Each search we will at most store all words in the queue
另外一种解法:
思路: 建一个map<长度,set<string>> 根据长度把输入的字典放到set里,然后从最长的长度所在的map[长度] 
开始枚举每个单词并缩减然后进行recursive call, 比如bdca 那么就可能缩成dca,bca,bda 然后去map[3]里找,
类推直到 word.size()==1 或找不到, 放个全局int去记最大长度。
注意找到后从字典里删除和word ladder一样 否则只能过4个case 会超时。

We can first sort word by length, so we can exit early.
public static int FindLongestChain(string[] words){
int len = words.Length;
HashSet<string> dict = new HashSet<string>();
foreach(string s in words)
dict.Add(s);
int res = 0;
foreach(string s in words){
//if the length of s is less or equal to res,
//then it's not possible to find a longer res starting from s
if(s.Length<=res || s.Length==1)
continue;
res = Math.Max(res,Bfs(s, dict));
}
return res;
}

//Find the length of longest chain starting from s
private static int Bfs(string s, HashSet<string> dict){
Queue<string> q = new Queue<string>();
int current = 1, next = 0;
int depth = 1; //If no chain, the length is 1
q.Enqueue(s);
while(current!=0){
string currWord = q.Dequeue();
current--;
for(int i=0;i<currWord.Length;i++){
StringBuilder sb = new StringBuilder(currWord);
sb.Remove(i,1);
string temp = sb.ToString();
if(dict.Contains(temp)){
if(temp.Length==1){
return depth+1; //the chain ends at next level, so depth++
}
q.Enqueue(temp);
next++;
}
}
if(current==0){
current = next;
next = 0;
depth++;
}
}
//if no return inside while loop, chain ends at last level, so return depth-1.
return depth-1;
}
http://buttercola.blogspot.com/2015/10/zenefits-oa-longest-chain.html

思路不错,不过有bug,你从maxLen开始算,但如果longestChain不是从maxLen的String开始的,你的code就得不到正确结果,应该loop一下所有的len,当然,如果len已经比longestChain短了,就可以结束了
    private static int max = 0;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        String[] dict = new String[n];
         
        for (int i = 0; i < n; i++) {
            dict[i] = scanner.next();
        }
         
        int result = longestWordChain(dict);
         
        System.out.println(result);
         
        scanner.close();
    }
     
    public static int longestWordChain(String[] dict) {
        if (dict == null || dict.length == 0) {
            return 0;
        }
         
        Map<Integer, Set<String>> map = new HashMap<>();
         
        // Fill the map
        int maxLen = 0;
         
        for (String token : dict) {
            int len = token.length();
            if (map.containsKey(len)) {
                map.get(len).add(token);
            } else {
                Set<String> words = new HashSet<>();
                words.add(token);
                map.put(len, words);
            }
             
            maxLen = Math.max(maxLen, len);
        }
         
        int result = longestWordChainHelper(maxLen, 1, map);
         
        return result;
    }
     
    private static int longestWordChainHelper(int curLen, int level,
        Map<Integer, Set<String>> dict) {
        if (curLen == 0) {
            return max;
        }
         
        if (dict.containsKey(curLen)) {
            Set<String> words = dict.get(curLen);
            Iterator<String> it = words.iterator();
            while (it.hasNext()) {
                String s = it.next();
                for (int i = 0; i < s.length(); i++) {
                    StringBuffer sb = new StringBuffer(s);
                    sb.deleteCharAt(i);
                    String nextStr = sb.toString();
                    if (dict.containsKey(curLen - 1) &&
                        dict.get(curLen - 1).contains(nextStr)) {
                        longestWordChainHelper(curLen - 1, level + 1, dict);
                    }
                }
                it.remove();
            }       
            max = Math.max(max, level);
        }
        return max;
    }
http://www.1point3acres.com/bbs/thread-131978-1-1.html
  HashMap<String, Integer> found = new HashMap<>();-google 1point3acres
  public int getLongestChainHelper(Set<String> dict, String word) {
    if(dict == null){
      return 0;
    }
    if(word.length() == 1){
      return 1;
    }
    if(found.containsKey(word)) {
      return found.get(word);
    }
    int maxLen = -1;
    for(int i = 0; i < word.length(); i++) {
       String newWord = removeCharAt(word, i);
       if(dict.contains(newWord)) {
            int longestChainNewWord = getLongestChainHelper(dict, newWord);. 涓€浜�-涓夊垎-鍦帮紝鐙鍙戝竷
            if(longestChainNewWord + 1 > maxLen) {-google 1point3acres
              maxLen = longestChainNewWord + 1;
            }
       }
    }
    maxLen = maxLen == -1 ? 1 : maxLen;
    found.put(word, maxLen);
    return maxLen;
  }. 鐣欏鐢宠璁哄潧-涓€浜╀笁鍒嗗湴

  public int getLongestChain(Set<String> dict) {
    if(dict == null){
      return 0;. Waral 鍗氬鏈夋洿澶氭枃绔�,
    }
    int longestChain = -1;
    for( String word : dict) {. more info on 1point3acres.com
      int currLongest = getLongestChainHelper(dict, word);
      if( currLongest > longestChain) {
        longestChain = currLongest;
      }
    }
    return longestChain;.1point3acres缃�
  }
https://blog.cancobanoglu.net/2016/09/18/interview-questions-string-chain/

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