Given a list of words, each word consists of English lowercase letters.
Let's say word1 is a predecessor of word2 if and only if we can add exactly one letter anywhere in word1 to make it equal to word2.  For example, "abc" is a predecessor of "abac".
A word chain is a sequence of words [word_1, word_2, ..., word_k] with k >= 1, where word_1 is a predecessor of word_2, word_2 is a predecessor of word_3, and so on.
Return the longest possible length of a word chain with words chosen from the given list of words.
 
Example 1:
Input: ["a","b","ba","bca","bda","bdca"]
Output: 4
Explanation: one of the longest word chain is "a","ba","bda","bdca".

 
Note:

1 <= words.length <= 1000
1 <= words[i].length <= 16
words[i] only consists of English lowercase letters.

Difficulty: interview

Starter code:

class Solution:
    def longestStrChain(self, words: List[str]) -> int:
        

Solutions:
["class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        by_length = collections.defaultdict(set)\n        for word in words:\n            by_length[len(word)].add(word)\n\n        longest = 1\n        seen = {*()}\n        mx = len(by_length)\n        mn = min(by_length)\n\n        for length in sorted(by_length, reverse=True):\n            if length - mn < longest:\n                break\n            for word in by_length[length]:\n                if length - mn < longest:\n                    break\n                if word in seen:\n                    continue\n                stk = [(word, length, 1)]\n                while stk:\n                    word, k, n = stk.pop()\n                    seen.add(word)\n                    if n > longest:\n                        longest = n\n                    for i in range(k):\n                        pre = word[:i] + word[i+1:]\n                        if pre not in seen and pre in by_length[k-1]:\n                            stk.append((pre, k-1, n+1))\n                if longest == mx:\n                    return longest\n\n        return longest   ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        by_length = collections.defaultdict(set)\n        for word in words:\n            by_length[len(word)].add(word)\n\n        longest = 1\n        seen = {*()} # set()\n        mx = len(by_length)\n        mn = min(by_length)\n        # in descending order\n        for length in sorted(by_length, reverse=True):\n            if length - mn < longest:\n                break\n            for word in by_length[length]:\n                if length - mn < longest:\n                    break\n                if word in seen:\n                    continue\n                stk = [(word, length, 1)]\n                while stk:\n                    word, k, n = stk.pop()\n                    seen.add(word)\n                    if n > longest:\n                        longest = n\n                    for i in range(k):\n                        pre = word[:i] + word[i+1:]\n                        if pre not in seen and pre in by_length[k-1]:\n                            stk.append((pre, k-1, n+1))\n               # if longest == mx:\n               #     return longest\n\n        return longest   ", "class Solution:\n    def issubsequence(self, str1, str2):\n        str1_pointer = 0\n        for i in range(len(str2)):\n            if str2[i] == str1[str1_pointer]:\n                str1_pointer += 1\n            if str1_pointer == len(str1):\n                return True\n        return False\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        word_lengths = {}\n        for i in words:\n            if len(i) not in word_lengths:\n                word_lengths[len(i)] = [i]\n            else:\n                word_lengths[len(i)].append(i)\n        max_length = max(list(word_lengths.keys()))\n        @lru_cache(None)\n        def dp(word):\n            if len(word) not in word_lengths:\n                return 0\n            if len(word) == max_length:\n                return 1\n            else:\n                max_chain = 1\n                for i in word_lengths[len(word) + 1]:\n                    if self.issubsequence(word, i):\n                        max_chain = max(max_chain, 1 + dp(i))\n                return max_chain\n        res = 0\n        for i in words:\n            res = max(res, dp(i))\n        return res", "class Solution:\n    _max = 0\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def dfs(cur, step):\n            if cur not in s:\n                return\n            if len(cur) == 0:\n                return\n            self._max = max(step, self._max)   \n            for i in range(len(cur)):\n                t = cur[:i] + cur[i+1:]\n                dfs(t, step+1)\n        s = set(words) \n        \n        for w in sorted(words, key = len, reverse = True):\n            dfs(w, 1)\n        return self._max\n", "from collections import defaultdict\n\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = defaultdict(lambda: 0)\n        for word in sorted(words, key=len):\n            dp[''.join(sorted(word))] = max(dp[''.join(sorted(word[:idx] + word[idx + 1:]))] for idx in range(len(word))) + 1\n        return max(dp.values())\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def compare(s1,s2):\n            if abs(len(s1)-len(s2)) != 1:\n                return False\n            if len(s2) > len(s1):\n                s1,s2=s2,s1\n            broke = False\n            s1,s2=list(s1),list(s2)\n            while s1 and s2:\n                a,b = s1.pop(), s2.pop()\n                if a != b:\n                    if broke or s1.pop() != b:\n                        return False\n                    broke = True\n            return True\n        \n        G = collections.defaultdict(list)\n        i = float('inf')\n        j = float('-inf')\n        for w in words:\n            i = min(i, len(w))\n            j = max(j, len(w))\n            G[len(w)].append((w,1))\n        res = 1\n        m = i+1\n        while m <= j:\n            for a,w1 in enumerate(G[m]):\n                for b,w2 in enumerate(G[m-1]):\n                    if compare(w1[0],w2[0]):\n                        G[m][a] = (w1[0],1+w2[1])\n                        res = max(1+w2[1],res)\n            m+=1\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def precedent(w1_c,w2_c):\n            if len(w1_c)>len(w2_c):\n                return False\n            \n            count = 0\n            for c in w2_c:\n                if c in w1_c:\n                    count+= w2_c[c]-w1_c[c]\n                else:\n                    count+= w2_c[c]\n            return count==1\n                    \n        minL = float('inf')\n        maxL = float('-inf')\n        \n        longest = 1\n        \n        len_count = collections.defaultdict(list)\n        subsequent_of_word = collections.defaultdict(int)\n        count_of_word = collections.defaultdict(Counter)\n        \n        for w in words:\n            len_count[len(w)].append(w)\n            subsequent_of_word[w] = 1\n            count_of_word[w] = Counter(w)\n            maxL= max(maxL,len(w))\n            minL= min(minL,len(w))\n\n        for i in range(maxL-1,minL-1,-1):\n            if i in len_count:\n                if i+1 in len_count:\n                    for w1 in len_count[i]:\n                        for w2 in len_count[i+1]:\n                            if precedent(count_of_word[w1],count_of_word[w2]):\n                                subsequent_of_word[w1] = max(subsequent_of_word[w1], subsequent_of_word[w2]+1)\n                                longest = max(longest, subsequent_of_word[w1])\n                                \n                else:\n                    for w in len_count[i]:\n                        subsequent_of_word[w]=1\n        \n        return longest\n                        \n        \n                    \n            \n        \n        \n            \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x: len(x), reverse=True)\n        minLen = len(words[-1])\n        \n        dic = set(words)\n        seen = set()\n        self.result = 0\n        for word in words:\n            if word not in seen:\n                length = 1\n                self.dfs(word, dic, seen, minLen, length)\n        \n        \n        return self.result\n    \n    def dfs(self, word, dic, seen, minLen, length):\n        self.result = max(self.result, length)\n        if len(word) == minLen:\n            return\n        \n        seen.add(word)\n        \n        for i in range(len(word)):\n            new = word[:i] + word[i+1:]\n            if new in dic:\n                self.dfs(new, dic, seen, minLen, length+1)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        all_chains = []\n        for word in words:\n            all_chains.extend(self.createChains(word, words))\n        return max(map(len,all_chains))\n\n    def createChains(self, word, words):\n        result = []\n        step = [word]\n        dictionary = set(words)\n\n        self.helper(word, step, dictionary, result)\n        return result\n\n    def helper(self, word, step, dictionary, result):\n        result.append(step[:])\n\n        for i in range(len(word)-1,-1, -1):\n            substring = word[:i]+word[i+1:]\n\n            if substring in dictionary: \n                step.append(substring) # choose\n                self.helper(substring, step, dictionary, result) # explore\n                step.pop() # unchoose", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def precedent(w1_c,w2_c):\n            count = 0\n            for c in w2_c:\n                if c in w1_c:\n                    count+= w2_c[c]-w1_c[c]\n                else:\n                    count+= w2_c[c]\n            return count==1\n                    \n        minL = float('inf')\n        maxL = float('-inf')\n        \n        longest = 1\n        \n        len_count = collections.defaultdict(list)\n        subsequent_of_word = collections.defaultdict(int)\n        count_of_word = collections.defaultdict(Counter)\n        \n        for w in words:\n            len_count[len(w)].append(w)\n            subsequent_of_word[w] = 1\n            count_of_word[w] = Counter(w)\n            maxL= max(maxL,len(w))\n            minL= min(minL,len(w))\n\n        for i in range(maxL-1,minL-1,-1):\n            if i in len_count:\n                if i+1 in len_count:\n                    for w1 in len_count[i]:\n                        for w2 in len_count[i+1]:\n                            if precedent(count_of_word[w1],count_of_word[w2]):\n                                subsequent_of_word[w1] = max(subsequent_of_word[w1], subsequent_of_word[w2]+1)\n                                longest = max(longest, subsequent_of_word[w1])\n                                \n                else:\n                    for w in len_count[i]:\n                        subsequent_of_word[w]=1\n        \n        return longest\n                        \n        \n                    \n            \n        \n        \n            \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        self._len_to_words = collections.defaultdict(list)\n        for w in words:\n            self._len_to_words[len(w)].append(w)\n        self._cache = {}\n            \n        self._visited = {}\n        max_so_far = 0\n        for w in words:\n            max_so_far = max(max_so_far, self._find_longest(w))\n        return max_so_far\n    \n    def _find_longest(self, w):\n        if w in self._visited:\n            return self._visited[w]\n        \n        len_w = len(w)\n        if len_w+1 not in self._len_to_words:\n            self._visited[w] = 1\n            return 1\n        \n        max_chain_len = 1\n        for cand in self._len_to_words[len_w+1]:\n            if self.is_predecessor(w, cand):\n                max_chain_len = max(max_chain_len, 1+self._find_longest(cand))\n        \n        self._visited[w] = max_chain_len\n        return max_chain_len\n        \n    def is_predecessor(self, w1, w2):\n        if (w1, w2) in self._cache:\n            return self._cache[(w1, w2)]\n        \n        is_p = True\n        if len(w1) + 1 != len(w2):\n            is_p = False\n        else:\n            count = {}\n            for c in w1:\n                if c in count:\n                    count[c] += 1\n                else:\n                    count[c] = 1\n            found_diff = False\n            for c in w2:\n                if c in count:\n                    count[c] -= 1\n                    if count[c] == 0:\n                        del count[c]\n                else:\n                    if found_diff:\n                        is_p = False\n                        break\n                    else:\n                        found_diff = True\n                        count[c] = 1\n        if is_p:\n            keys = list(count.keys())\n            is_p = len(keys) == 1 and count[keys[0]] == 1\n        \n        self._cache[(w1, w2)] = is_p\n        return is_p", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def precedent(w1_c,w2_c):\n            count = 0\n            for c in w2_c:\n                if c in w1_c:\n                    count+= w2_c[c]-w1_c[c]\n                else:\n                    count+= w2_c[c]\n            return count==1\n                    \n        minL = float('inf')\n        maxL = float('-inf')\n        \n        longest = 1\n        \n        len_count = collections.defaultdict(list)\n        subsequent_of_word = collections.defaultdict(int)\n        count_of_word = collections.defaultdict(Counter)\n        \n        for w in words:\n            len_count[len(w)].append(w)\n            subsequent_of_word[w] = 1\n            count_of_word[w] = Counter(w)\n            maxL= max(maxL,len(w))\n            minL= min(minL,len(w))\n\n        for i in range(maxL,minL-1,-1):\n            if i in len_count:\n                if i+1 in len_count:\n                    for w1 in len_count[i]:\n                        for w2 in len_count[i+1]:\n                            if precedent(count_of_word[w1],count_of_word[w2]):\n                                subsequent_of_word[w1] = max(subsequent_of_word[w1], subsequent_of_word[w2]+1)\n                                longest = max(longest, subsequent_of_word[w1])\n                                \n                else:\n                    for w in len_count[i]:\n                        subsequent_of_word[w]=1\n        \n        return longest\n                        \n        \n                    \n            \n        \n        \n            \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def f(x, y):\n            if len(x) != len(y) - 1:\n                return False\n            p = len(x)\n            for i in range(len(x)):\n                if x[i] != y[i]:\n                    p = i\n                    break\n            \n            for i in range(p, len(x)):\n                if x[i] != y[i + 1]:\n                    return False\n            return True\n\n        words.sort(key=lambda x:len(x))\n        d = {words[i]: i for i in range(len(words))}\n        \n        a = []\n        for _ in range(len(words)):\n            a.append([False] * len(words))\n            \n        \n        for j in range(len(words)):\n            for k in range(len(words[j])):\n                i = d.get(words[j][:k] + words[j][k + 1:], -1)\n                if i >= 0:\n                    a[i][j] = True\n                \n        # print(a)\n                \n        dp = [1] * len(words)\n        for i in range(1, len(words)):\n            for j in range(i):\n                if a[j][i]:\n                    dp[i] = max(dp[i], dp[j] + 1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        hashtable = {}\n        record = [1 for i in range(17)]\n        for w in words:\n            if(len(w) not in hashtable):\n                hashtable[len(w)] = [{w:1}]\n            else:\n                hashtable[len(w)].append({w:1})\n        # print(hashtable)\n        for i in range(17):\n            if(i in hashtable):\n                if(i-1 in hashtable):\n                    # print(hashtable[i])\n                    n = 0\n                    tmp_max = 0\n                    for word in hashtable[i]:\n                        word = list(word.keys())[0]\n                        m = 0\n                        for preword in hashtable[i-1]:\n                            preword =  list(preword.keys())[0]\n                            if(self.ispreword(preword,word)):\n                                hashtable[i][n][word] = max(hashtable[i-1][m][preword] + 1, hashtable[i][n][word] )\n                                tmp_max = max(tmp_max, hashtable[i][n][word])\n                            m+=1\n                        n+=1\n                    record[i] = tmp_max\n                    # print( hashtable[i])\n        \n        # print(record)\n        return max(record)\n    \n    def ispreword(self,preword, word):\n        check = [i for i in word]\n        for w in preword:\n            if w not in check:\n                return False\n            else:\n                check.remove(w)\n        return True", "from functools import lru_cache\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        d = collections.defaultdict(list)\n        for w in words:\n            d[len(w)].append(w)\n        \n        @lru_cache(None)\n        def dp(w):\n            if len(w) == 1:\n                return 1\n            for candidate in d[len(w) - 1]:\n                for i in range(len(w)):\n                    if candidate == w[:i] + w[i+1:]:\n                        return dp(candidate) + 1\n            return 1\n        \n        return max(dp(i) for i in words)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        N = len(words)\n        if N<2: return N\n        \n        words.sort(key=len)\n        Table = {word:1 for word in words}\n        result = 1\n        for word in words:\n            for j in range(len(word)):\n                subword = word[:j] + word[j+1:]\n                if subword in Table and Table[subword]>=Table[word]:\n                    Table[word] = Table[subword] + 1\n            if Table[word] > result:\n                result = Table[word]\n        \n        return result", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # group by length\n        length2words = defaultdict(list)\n        for w in words:\n            length2words[len(w)].append(w)\n    \n        # for each length l -> check words in previous l-1 that form longer chain\n        word2chain = dict()\n        for l in sorted(length2words):\n            for w in length2words[l]:\n                word2chain[w] = 1\n                if l-1 not in length2words:\n                    continue\n                for prev_w in length2words[l-1]:\n                    if word2chain[prev_w]+1 < word2chain[w]:\n                        continue\n                    if self.isPredecessor(prev_w, w):\n                        word2chain[w] = max(word2chain[w], word2chain[prev_w]+1)\n        \n        return max(word2chain.values())\n        \n    def isPredecessor(self, word1, word2):\n        # try skip letter in word2\n        for i in range(len(word2)):\n            skip = word2[:i]+word2[i+1:]\n            if skip == word1:\n                return True\n        return False", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # group by length\n        length2words = defaultdict(list)\n        for w in words:\n            length2words[len(w)].append(w)\n    \n        # for each length l -> check words in previous l-1 that form longer chain\n        word2chain = {w: 1 for w in words}\n        for l in sorted(length2words):\n            if l-1 not in length2words:\n                continue\n            for w in length2words[l]:\n                for prev_w in length2words[l-1]:\n                    if word2chain[prev_w]+1 < word2chain[w]:\n                        continue\n                    if self.isPredecessor(prev_w, w):\n                        word2chain[w] = max(word2chain[w], word2chain[prev_w]+1)\n        \n        return max(word2chain.values())\n        \n    def isPredecessor(self, word1, word2):\n        # try skip letter in word2\n        for i in range(len(word2)):\n            skip = word2[:i]+word2[i+1:]\n            if skip == word1:\n                return True\n        return False", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def longest_chain(word, word_set, memo):\n            \n            if word not in word_set:\n                return 0\n            \n            if word not in memo:\n                longest = 1\n                for i in range(len(word)):\n                    next_word = word[:i] + word[i+1:]\n                    longest = max(1 + longest_chain(next_word, word_set, memo), longest)\n                memo[word] = longest\n                \n            return memo[word]\n        \n        \n        \n        longest = 0\n        for word in words:\n            longest = max(longest_chain(word, set(words), {}), longest)\n        return longest\n    \n#     n = len(words)\n#     m = max length of word in words\n    \n#     Time: O(n * m!)\n#     Space: O(n*m)\n    \n", "from collections import defaultdict, deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) <= 1:\n            return len(words)\n        \n        graph_dict, len_words_dict = self.getGraphDict(words)\n \n        word_lengths = list(len_words_dict.keys())\n        word_lengths.sort()\n        \n        length_index_dict = defaultdict()\n        for i in range(len(word_lengths)):\n            length_index_dict[word_lengths[i]] = i\n        \n        return self.bfsWordChain(graph_dict, len_words_dict, word_lengths, length_index_dict)\n    \n    def bfsWordChain(self, graph_dict, len_words_dict, word_lengths, length_index_dict):\n        word_lenghts_index = 0\n        initial_words = len_words_dict[word_lengths[0]]\n        \n        max_possible_length = len(word_lengths)\n        curr_length = 1\n\n        visited = set()\n        \n        queue = deque()\n        for word in initial_words:\n            queue.append((word, 1))\n            visited.add(word)\n        \n        max_len_so_far = 1\n        \n        while queue:\n            this_item = queue.popleft()\n            this_word = this_item[0]\n            this_chain_len = this_item[1]\n            max_len_so_far = max(max_len_so_far, this_chain_len)\n            this_item_possible_length = this_chain_len + len(word_lengths) - length_index_dict[len(this_word)]\n            if this_item_possible_length > max_len_so_far:\n                neighbors = graph_dict[this_word]\n                for neighbor in neighbors:\n                    if neighbor not in visited:\n                        visited.add(neighbor)\n                        queue.append((neighbor, this_chain_len + 1))\n\n                if len(queue) == 0:\n                    word_found = False\n                    for word_length in word_lengths:\n                        for word in len_words_dict[word_length]:\n                            if word not in visited and not word_found:\n                                queue.append((word, 1))\n                                visited.add(word)\n                                word_found = True\n                                break\n        \n        return max_len_so_far\n            \n        \n        \n\n    \n    def getGraphDict(self, words):\n        len_words_dict = defaultdict(list)\n        for word in words:\n            len_words_dict[len(word)].append(word)\n        word_lenghts_arr = []\n        graph_dict = defaultdict(list)\n\n        for word_length in len_words_dict:\n            for predecessor in len_words_dict[word_length]:\n                if word_length + 1 in len_words_dict:\n                    for word in len_words_dict[word_length + 1]:\n                        if self.isPredecessor(predecessor, word):\n                            graph_dict[predecessor].append(word)\n\n        return graph_dict, len_words_dict\n    \n    def isPredecessor(self, predecessor, word):\n        predecessor_index = 0\n        word_index = 0\n        while predecessor_index < len(predecessor) and word_index < len(word):\n            if predecessor[predecessor_index] == word[word_index]:\n                predecessor_index += 1\n                word_index += 1\n            else:\n                word_index += 1\n        \n        if word_index == predecessor_index + 1 or word_index == predecessor_index:\n            return True\n        else:\n            return False\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        d = collections.defaultdict(list)\n        for word in words:\n            d[len(word)].append(word)\n        \n        lengths = sorted(list(d.keys()))\n        self.mem = {}\n        \n        def dfs(word):\n            if len(word)==lengths[-1]:\n                return 1\n            if word in self.mem:\n                return self.mem[word]\n            \n            nxt_length = 0\n            for nxt_word in d[len(word)+1]:\n                for j in range(len(nxt_word)):\n                    if word==nxt_word[:j]+nxt_word[j+1:]:\n                        nxt_length = max(nxt_length, dfs(nxt_word))\n            \n            self.mem[word] = nxt_length+1\n            return nxt_length+1\n        \n        res = 0\n        for word in words:\n            res = max(res,dfs(word))\n            \n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:   return 0\n        words.sort(key=len)\n        #print(words)\n        \n        def isNeighbor(a,b):\n            if len(a)+1 != len(b):  return False\n            if a==b[1:] or a==b[:-1]:   return True\n            ia,ib = 0,0\n            flag = True\n            while ia < len(a):\n                if a[ia]==b[ib]:\n                    ia,ib = ia+1,ib+1\n                elif flag:\n                    flag = False\n                    ib += 1\n                else:\n                    return False\n            return True\n        \n        dp = [1] * len(words)\n        ans = 0\n        #longest so far\n        for i in range(len(words)):\n            for j in range(i):\n                if len(words[j])+1<len(words[i]):\n                    continue\n                elif len(words[j])+1>len(words[i]):\n                    break\n                else:\n                    if isNeighbor(words[j],words[i]):\n                        dp[i] = max(dp[i],dp[j]+1)\n            ans = max(ans,dp[i])\n        #print(dp)\n        return ans", "class Solution:\n  #[\\\"a\\\",\\\"b\\\",\\\"ba\\\",\\\"bca\\\",\\\"bda\\\",\\\"bdca\\\"]\n  def can_convert(self, word1, word2):\n    for missing_idx in range(len(word2)):\n      if word2[:missing_idx] + word2[missing_idx+1:] == word1:\n          return True\n    return False\n    \n\n  def longestStrChain(self, words: List[str]) -> int:\n    #{1: [0,1], 2: [2], 3: [3,4], 4: [5]}\n    words_by_length = collections.defaultdict(list)\n    #keep list of word idxs mapped to their length\n    for idx, word in enumerate(words):\n        words_by_length[len(word)].append(idx)\n\n    #{3: [5], 4: [5], 0: [2], 1: [2], 2: [3,4]}\n    #[0,0,2,1,1,2]\n    adj_list = collections.defaultdict(list)\n    #word idx can act as a node id\n\n    indegree = [0]*len(words)\n    for length in words_by_length:\n      #edge only poss if there are words of length + 1\n      if (length+1) in words_by_length:\n        for word_1_idx in  words_by_length[length]:\n          for word_2_idx in words_by_length[length + 1]:\n            if self.can_convert(words[word_1_idx], words[word_2_idx]):\n              adj_list[word_1_idx].append(word_2_idx)\n              indegree[word_2_idx] += 1\n        \n            \n\n    #[5]\n    queue = collections.deque([word_idx for word_idx in range(len(words)) if indegree[word_idx] == 0])\n\n    max_length = 0\n    while(queue):\n        length = len(queue)\n        max_length += 1\n        for i in range(length):\n            curr_word_idx = queue.popleft()\n            for successor in adj_list[curr_word_idx]:\n                indegree[successor] -= 1\n                if indegree[successor] == 0:\n                    queue.append(successor)\n\n\n    return max_length", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        d = dict()\n        for word in words:\n            d[word] = 1\n        longest = 1\n        for word in sorted(words, key=len):\n            for i in range(len(word)):\n                prev = word[:i] + word[i + 1:]\n                if prev in d:\n                    d[word] = max(d[word], d[prev] + 1)\n            longest = max(longest, d[word])\n        return longest", "from collections import defaultdict, deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) <= 1:\n            return len(words)\n        \n        graph_dict, len_words_dict = self.getGraphDict(words)\n \n        word_lengths = list(len_words_dict.keys())\n        word_lengths.sort()\n        \n        return self.bfsWordChain(graph_dict, len_words_dict, word_lengths)\n    \n    def bfsWordChain(self, graph_dict, len_words_dict, word_lengths):\n        word_lenghts_index = 0\n        initial_words = len_words_dict[word_lengths[0]]\n        \n        max_possible_length = len(word_lengths)\n        curr_length = 1\n\n        visited = set()\n        \n        queue = deque()\n        for word in initial_words:\n            queue.append((word, 1))\n            visited.add(word)\n        \n        max_len_so_far = 1\n        \n        while queue:\n            this_item = queue.popleft()\n            this_word = this_item[0]\n            this_chain_len = this_item[1]\n            max_len_so_far = max(max_len_so_far, this_chain_len)\n            # this_item_possible_length = this_chain_len + len(word_lengths[])\n            neighbors = graph_dict[this_word]\n            for neighbor in neighbors:\n                if neighbor not in visited:\n                    visited.add(neighbor)\n                    queue.append((neighbor, this_chain_len + 1))\n            \n            if len(queue) == 0:\n                word_found = False\n                for word_length in word_lengths:\n                    for word in len_words_dict[word_length]:\n                        if word not in visited and not word_found:\n                            queue.append((word, 1))\n                            visited.add(word)\n                            word_found = True\n                            break\n        \n        return max_len_so_far\n            \n        \n        \n\n    \n    def getGraphDict(self, words):\n        len_words_dict = defaultdict(list)\n        for word in words:\n            len_words_dict[len(word)].append(word)\n        word_lenghts_arr = []\n        graph_dict = defaultdict(list)\n        for word_length in len_words_dict:\n            for predecessor in len_words_dict[word_length]:\n                if word_length + 1 in len_words_dict:\n                    for word in len_words_dict[word_length + 1]:\n                        if self.isPredecessor(predecessor, word):\n                            graph_dict[predecessor].append(word)\n\n        return graph_dict, len_words_dict\n    \n    def isPredecessor(self, predecessor, word):\n        predecessor_index = 0\n        word_index = 0\n        while predecessor_index < len(predecessor) and word_index < len(word):\n            if predecessor[predecessor_index] == word[word_index]:\n                predecessor_index += 1\n                word_index += 1\n            else:\n                word_index += 1\n        \n        if word_index == predecessor_index + 1 or word_index == predecessor_index:\n            return True\n        else:\n            return False\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # sort by decreasing length\n        # define vector L of length len(words) such that it's the longest \n        # word chain starting from that word\n        # then recuriosn is L_k = 1 if it is not predecessor of any 1 longer words\n        # otherwise it is 1 + max L_j for j such that k is predecessor of them\n        \n        lengths = [len(word) for word in words]\n        wordsSorted = [x for _,x in sorted(zip(lengths,words),reverse = True)]\n        \n        print(wordsSorted)\n        L = [1]*len(wordsSorted)\n        maxLength = max(lengths)\n        for k in range(0, len(L)):\n            lenWord = len(wordsSorted[k])\n            if  lenWord == maxLength:\n                L[k] = 1\n            else: \n                for l in range(k):\n                    if len(wordsSorted[l]) == lenWord+1 and (set(wordsSorted[l]) & set(wordsSorted[k])) == set(wordsSorted[k]):\n                        L[k] = max(L[k], 1 + L[l])\n        return(max(L))\n                    \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        cnt = [[] for i in range(16)]\n        min_l = 16\n        for i in words:\n            min_l = min([min_l,len(i)])\n            cnt[len(i)-1].append(i)\n        # print(cnt)\n        def match(a,b):\n            i = j = 0\n            cnt = 0\n            while j < len(b):\n                if i < len(a) and a[i] == b[j]:\n                    i += 1\n                    j += 1\n                else:\n                    j += 1\n                    cnt += 1\n            return cnt == 1\n            \n        def topdown(curr_words):\n            if len(curr_words) == 16:\n                return 1\n            if curr_words in dp:\n                return dp[curr_words]\n            \n            dp[curr_words] = 1\n            for i in cnt[len(curr_words)]:\n                if match(curr_words,i):\n                    if not i in dp:\n                        dp[i] = topdown(i)+1\n                    dp[curr_words] = max([dp[curr_words],dp[i]])\n            return dp[curr_words]\n        ans = 0\n        for i in range(min_l-1,16):\n            for j in cnt[i]:\n                if j in dp:\n                    ans = max([ans,dp[j]])\n                else:\n                    ans = max([ans,topdown(j)])\n                # print(dp,i)\n        \n        return ans\n", "from collections import deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        return self.run_graph_solution(words)\n        # return self.run_dp_solution(words)\n    \n    def run_dp_solution(self, words):\n        pass\n        \n    def run_graph_solution(self, words):\n        graph = {word: [] for word in words}\n        lengths = {k: [] for k in range(1, 17)}\n        into = {}\n        min_len = 17\n        max_len = 1\n        for word in words:\n            lengths[len(word)].append(word)\n            min_len = min(len(word), min_len)\n            max_len = max(len(word), max_len)\n                    \n        for k in range(min_len, max_len):\n            for word1 in lengths[k]:\n                for word2 in lengths[k + 1]:\n                    for i in range(len(word2)):\n                        if word2[:i] + word2[i+1:] == word1:\n                            graph[word1].append(word2)\n                            into[word2] = True\n        # return graph\n        \n        sources = [word for word in words if word not in into]\n        max_len = 0\n        for s in sources:\n            max_len = max(max_len, self.run_bfs(s, graph))\n        return max_len\n                \n    def run_bfs(self, s, graph):\n        queue = deque(maxlen=len(list(graph.keys())))\n        queue.appendleft((s, 1))\n        summary = []\n        \n        while len(queue) > 0:\n            current_node, cur_len = queue.pop()\n            for word in graph[current_node]:\n                queue.appendleft((word, cur_len + 1))\n            summary.append(cur_len)\n        \n        return summary[-1]\n    \n    \n            \n            \n        \n        \n        \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words_len = [[] for _ in range(16)]\n        graph = {word: [] for word in words}\n        \n        for word in words:\n            words_len[len(word) - 1].append(word)\n    \n        def predecessor(word1, word2):\n            for i in range(len(word2)):\n                if word2[:i] + word2[i+1:] == word1:\n                    return True\n            \n            return False\n        \n        for i in range(len(words_len) - 1):\n            words_1 = words_len[i]\n            words_2 = words_len[i + 1]\n            \n            for word1 in words_1:\n                for word2 in words_2:\n                    if predecessor(word1, word2):\n                        graph[word1].append(word2)\n        \n\n        memo = {word: -1 for word in words}\n        \n        def dfs(word):\n            t = 1\n            \n            if memo[word] == -1:\n                for w in graph[word]:\n                    t = max(t, 1 + dfs(w))\n            \n                memo[word] = t\n                \n            return memo[word]\n        \n        \n        lpl = 0\n        \n        for words in words_len:\n            for word in words:\n                lpl = max(lpl, dfs(word))\n        \n        return lpl\n        \n        \n", "#Longest increasing sequence.\n# Instead, you can store all the words in a hashmap with their indexes. Now, for \n# Every word, try to delete one character and see if it is present in the map. But you need to sort the array first.\nfrom collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        chain = defaultdict(list)\n        def checkPredecessor(w1, w2):\n            for i in range(len(w2)):\n                if w2[:i] + w2[i + 1:] == w1:\n                    return True\n            return False\n        for idx, word in enumerate(words):\n            chain[len(word)].append((word, idx))\n        dp = [0] * len(words)\n        \n        i = 1\n        while(i < 17):\n            for word, dp_idx in chain[i]:\n                if i - 1 in chain:\n                    for checkWord, dp_jdx in chain[i - 1]:\n                        if checkPredecessor(checkWord, word):\n                            dp[dp_idx] = max(dp[dp_idx], 1 + dp[dp_jdx])\n            i += 1\n        return max(dp) + 1\n            \n        \n", "from collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        #words.sort(key = lambda x: len(x))\n        chain = defaultdict(list)\n        def checkPredecessor(w1, w2):\n            for i in range(len(w2)):\n                if w2[:i] + w2[i + 1:] == w1:\n                    return True\n            return False\n        for idx, word in enumerate(words):\n            chain[len(word)].append((word, idx))\n        dp = [0] * len(words)\n        \n        i = 1\n        while(i < 17):\n            for word, dp_idx in chain[i]:\n                if i - 1 in chain:\n                    for checkWord, dp_jdx in chain[i - 1]:\n                        if checkPredecessor(checkWord, word):\n                            dp[dp_idx] = max(dp[dp_idx], 1 + dp[dp_jdx])\n            i += 1\n        return max(dp) + 1\n            \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def check(i,j):\n            w1 = words[i]\n            w2 = words[j]\n            \n            for k in range(len(w2)):\n                if w1 == (w2[:k] + w2[k+1:]):\n                    return True\n            return False\n        \n        buckets = defaultdict(list)\n        for i,word in enumerate(words):\n            l = len(word)\n            buckets[l] += [i]\n            \n        g = defaultdict(list)\n        for key in buckets:\n            if key + 1 in buckets:\n                for i in buckets[key]:\n                    for j in buckets[key+1]:\n                        if check(i,j):\n                            g[i] += [j]\n                \n        ans = 0\n        seen = set()\n        for key in sorted(buckets.keys()):\n            for i in buckets[key]:\n                stack = [[1,i]]\n                while stack:\n                    level, node = stack.pop()\n                    ans = max(ans, level)\n                    if node in seen:\n                        continue\n                    seen.add(node)\n                    \n                    if node in g:\n                        for child in g[node]:\n                            if child not in seen:\n                                stack += [[level+1, child]]\n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        result = 1\n        for word in sorted(words,key = len):\n            dp[word] = 1\n            for i in range(len(word)):\n                prev = word[:i] + word[i + 1:]\n                if prev in dp:\n                    dp[word] = max(dp[word],dp[prev] + 1)\n                    result = max(result,dp[word])\n        return result\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        lengthMap = {}\n        for word in words:\n            n = len(word)\n            if n not in lengthMap:\n                lengthMap[n] = []\n            lengthMap[n].append(word)\n            \n        arr = [0 for i in range(len(words))]\n        dp = {i : -1 for i in words} \n        res = 1\n        \n        for i in range(len(words)):\n            arr[i] = self.get_longest(dp, lengthMap, words[i])\n            res = max(arr[i], res)\n            \n        print (arr)\n        return res\n    \n    \n        # Standard DP solution \n        \n        # dp = {i: 0 for i in words}\n        # words = sorted(words, key=len)\n        # for w in words:\n        #     tmp = [0]\n        #     for i in range(len(w)):\n        #         if w[:i] + w[i+1:] in dp:\n        #             tmp.append(dp[w[:i] + w[i+1:]])\n        #         dp[w] = max(tmp) + 1\n        # return max(dp.values())\n    \n    \n    \n    def get_longest(self, dp, lengthMap, word):\n        if dp[word] != -1:\n            return dp[word]\n        \n        if len(word) + 1 not in lengthMap:\n            return 1\n        \n        res = 0\n        for item in lengthMap[len(word) + 1]:\n            if self.only_one_diff(word, item):\n                res = max(res, self.get_longest(dp, lengthMap, item))\n        \n        dp[word] = res + 1\n        return res + 1\n\n    \n    def only_one_diff(self, word1, word2):\n        for i in range(len(word2)):\n            if word2[:i] + word2[i + 1:] == word1:\n                return True\n        return False\n            \n    \n\n            \n            \n", "# DFS | Time: O(n * k) | Space: O(n)\n# n: len(words)\n# k: length of each word\nclass Solution:\n    \n    # @param words: List[str]\n    # @return int\n    def longestStrChain(self, words):\n        if not words:\n            return 0\n\n        # build word table\n        wordTable = self.buildWordTable(words) # { length: list of words }\n\n        # dfs - search from shortest word to longest word\n        maxLen = 0\n        visited = set()\n        for wordLen in range(min(wordTable), max(wordTable) + 1):\n            for word in wordTable[wordLen]:\n                if word not in visited:\n                    maxLen = max(maxLen, self.dfs(wordTable, word, visited))\n\n        return maxLen\n\n    # Derive word table.\n    # Key: word length.\n    # Value: list of words that have length of key.\n    # @param words: List[str]\n    # @return dict({ int: List[str] })\n    def buildWordTable(self, words):\n\n        # initialize\n        wordTable = {} # { length: list of words }\n\n        for word in words:\n            if len(word) not in wordTable:\n                wordTable[len(word)] = []\n            wordTable[len(word)].append(word)\n\n        return wordTable\n\n    # DFS - search the successors and find the longest chain\n    #   - Apply Divide & Conquer coding framework\n    # @param wordTable: dict({ int: List[str] })\n    # @param word: str\n    # @param visited: set(str)\n    # @return int\n    def dfs(self, wordTable, word, visited):\n\n        # initialize\n        maxLen = 0\n        visited.add(word)\n\n        # divide\n        #   - Find successors and update the max length that subtasks responded\n        if len(word) + 1 in wordTable:\n            for neighbor in wordTable[len(word) + 1]:\n                if self.isAncestor(word, neighbor):\n                    maxLen = max(maxLen, self.dfs(wordTable, neighbor, visited))\n\n        # conquer\n        #   - Calculate the max length found\n        #   - +1 to count itself\n        return maxLen + 1\n\n    # @param ancestor: str\n    # @param successor: str\n    # @return bool\n    def isAncestor(self, ancestor, successor):\n        if len(ancestor) + 1 != len(successor):\n            return False\n\n        # initialize\n        i, j = 0, 0\n\n        while i < len(ancestor) and j < len(successor):\n            if ancestor[i] != successor[j]:\n                j += 1\n                continue\n            else:\n                i += 1\n                j += 1\n\n        return i == j or i == j - 1\n", "class Solution:\n    \n    \n    def isChild(self, parent, possible_child):\n        for i in range(len(possible_child)):\n            if possible_child[:i] + possible_child[i+1:] == parent:\n                return True \n        return False\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        \n        # an intutitve idea is to create a graph of the given words, where every node is a word, and is a predecessor to all of its children. We can then simply DFS from root to node and find the longest path.\n        # the DFS would take O(n) where n is the length of words.\n        # Challenge: how to construct graph? We can loop once and bucket words by their length, and create a node per word, then starting from the smallest word length i, find all possible children of length i+1 and add them as edges do this until the end. \n        # bucketing and creating graph nodes would take O(n), connecting nodes would also take o(n) since we only check two buckets at a time linearly, and those buckets at most contain n nodes (and in that case other buckets are empty), so its O(n)\n        \n        \n        graph = {}\n        # word length buckets \n        word_lens = [[] for _ in range(17)]\n        # create nodes and bucket\n        for w in words:\n            graph[w] = []\n            word_lens[len(w)].append(w)\n        \n        # connect graph\n        for i in range(1,16):\n            parents = word_lens[i]\n            possible_children = word_lens[i+1]\n            for p in parents: \n                for c in possible_children:\n                    # check if c can possibly be a child of p\n                    # it is a possible child if \n                    if self.isChild(p,c):\n                        graph[p].append(c)\n        # do DFS \n        longest_len = 0\n        # word: longest path to it pair. avoids revisiting node if we got to it a longer way before\n        visited = {}\n        # sorting ensures we visit nodes through the longest path \n        sorted_keys = sorted(graph.keys())\n        for node in sorted_keys:\n            to_visit = [(node,1)]\n            while(len(to_visit) != 0):\n                cur_node,depth = to_visit.pop()\n                visited[cur_node] = depth\n                longest_len = max(depth, longest_len)\n                for child in graph[cur_node]: \n                    if child not in visited:\n                        to_visit.append((child,depth+1))\n                    else: \n                        if depth+1 > visited[child]:\n                            to_visit.append((child,depth+1))\n        return longest_len", "from collections import deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        return self.run_graph_solution(words)\n        # return self.run_dp_solution(words)\n    \n    def run_dp_solution(self, words):\n        \n        mem = {}\n        def inner(w):\n            if w in mem or len(w) == 0:\n                return\n            \n            max_per_w = 0\n            for j in range(len(w)):\n                cur = w[:j] + w[j+1:]\n                if cur in mem:\n                    val = mem[cur] + 1\n                else:\n                    val = inner(cur) + 1\n                if val > max_per_w:\n                    max_per_w = val\n            mem[w] = max_per_w\n            return\n        \n        return max(mem.values())\n        \n    def run_graph_solution(self, words):\n        graph = {word: [] for word in words}\n        lengths = {k: [] for k in range(1, 17)}\n        into = {}\n        min_len = 17\n        max_len = 1\n        for word in words:\n            lengths[len(word)].append(word)\n            min_len = min(len(word), min_len)\n            max_len = max(len(word), max_len)\n                    \n        for k in range(min_len, max_len):\n            for word1 in lengths[k]:\n                for word2 in lengths[k + 1]:\n                    for i in range(len(word2)):\n                        if word2[:i] + word2[i+1:] == word1:\n                            graph[word1].append(word2)\n                            into[word2] = True     \n                            \n        sources = [word for word in words if word not in into]\n        max_len = 0\n        for s in sources:\n            max_len = max(max_len, self.run_bfs(s, graph))\n        return max_len\n                \n    def run_bfs(self, s, graph):\n        queue = deque(maxlen=len(list(graph.keys())))\n        queue.appendleft((s, 1))\n        summary = []\n        \n        while len(queue) > 0:\n            current_node, cur_len = queue.pop()\n            for word in graph[current_node]:\n                queue.appendleft((word, cur_len + 1))\n            summary.append(cur_len)\n        \n        return summary[-1]\n    \n    \n            \n            \n        \n        \n        \n        \n        \n", "class Solution:\n    \n    \n    def isChild(self, parent, possible_child):\n        for i in range(len(possible_child)):\n            if possible_child[:i] + possible_child[i+1:] == parent:\n                return True \n        return False\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        \n        # an intutitve idea is to create a graph of the given words, where every node is a word, and is a predecessor to all of its children. We can then simply DFS from root to node and find the longest path.\n        # the DFS would take O(n) where n is the length of words.\n        # Challenge: how to construct graph? We can loop once and bucket words by their length, and create a node per word, then starting from the smallest word length i, find all possible children of length i+1 and add them as edges do this until the end. \n        # bucketing and creating graph nodes would take O(n), connecting nodes would also take o(n) since we only check two buckets at a time linearly, and those buckets at most contain n nodes (and in that case other buckets are empty), so its O(n)\n        \n        \n        graph = {}\n        # word length buckets \n        word_lens = [[] for _ in range(17)]\n        # create nodes and bucket\n        for w in words:\n            graph[w] = []\n            word_lens[len(w)].append(w)\n        \n        # connect graph\n        for i in range(1,16):\n            parents = word_lens[i]\n            possible_children = word_lens[i+1]\n            for p in parents: \n                for c in possible_children:\n                    # check if c can possibly be a child of p\n                    # it is a possible child if \n                    if self.isChild(p,c):\n                        graph[p].append(c)\n       # do DFS \n        longest_len = 0\n        for node in graph.keys():\n            to_visit = [(node,1)]\n            \n            while(len(to_visit) != 0):\n                cur_node,depth = to_visit.pop()\n                longest_len = max(depth, longest_len)\n                for child in graph[cur_node]: \n                    to_visit.append((child,depth+1))\n            \n        return longest_len", "\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        print(words)\n        if not words:\n            return 0\n            \n        max_chain_dp = {}\n        max_len = 1\n        for i in range(len(words)):\n            word_len = len(words[i])\n            max_chain_dp[words[i]] = 1\n            for j in range(i-1, -1, -1):\n                if len(words[j]) == word_len:\n                    continue\n                elif len(words[j]) + 1 == word_len:\n                    if self.isChain(words[j], words[i]):\n                        max_chain_dp[words[i]] = max(1 + max_chain_dp[words[j]], max_chain_dp[words[i]])\n                        max_len = max(max_chain_dp[words[i]], max_len)\n                else:\n                    break\n        return max_len\n                \n                \n    def isChain(self, word1, word2):\n        if len(word2) - len(word1) > 1:\n            return False\n        added = False\n        i, j = 0, 0\n        while i < len(word1) or j < len(word2):\n            if i < len(word1) and word1[i] == word2[j]:\n                i += 1\n                j += 1\n            else:\n                if added:\n                    return False\n                else:\n                    j += 1\n                    added = True\n\n        if i == len(word1) and j == len(word2):\n            return True\n\n\n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        self._len_to_words = collections.defaultdict(list)\n        for w in words:\n            self._len_to_words[len(w)].append(w)\n        if len(self._len_to_words) == 1:\n            return 1\n        self._cache = {}\n            \n        self._visited = {}\n        max_so_far = 0\n        for w in words:\n            max_so_far = max(max_so_far, self._find_longest(w))\n        return max_so_far\n    \n    def _find_longest(self, w):\n        if w in self._visited:\n            return self._visited[w]\n        \n        len_w = len(w)\n        if len_w+1 not in self._len_to_words:\n            self._visited[w] = 1\n            return 1\n        \n        max_chain_len = 1\n        for cand in self._len_to_words[len_w+1]:\n            if self.is_predecessor(w, cand):\n                max_chain_len = max(max_chain_len, 1+self._find_longest(cand))\n        \n        self._visited[w] = max_chain_len\n        return max_chain_len\n        \n    def is_predecessor(self, w1, w2):\n        if (w1, w2) in self._cache:\n            return self._cache[(w1, w2)]\n        \n        is_p = True\n        if len(w1) + 1 != len(w2):\n            is_p = False\n        else:\n            count = {}\n            for c in w1:\n                if c in count:\n                    count[c] += 1\n                else:\n                    count[c] = 1\n            found_diff = False\n            for c in w2:\n                if c in count:\n                    count[c] -= 1\n                    if count[c] == 0:\n                        del count[c]\n                else:\n                    if found_diff:\n                        is_p = False\n                        break\n                    else:\n                        found_diff = True\n                        count[c] = 1\n        if is_p:\n            keys = list(count.keys())\n            is_p = len(keys) == 1 and count[keys[0]] == 1\n        \n        self._cache[(w1, w2)] = is_p\n        return is_p", "class Solution:\n    def isPredecessor(self, word1, word2): \n        for i in range(1, len(word2) + 1): \n            if (word2[:i-1] + word2[i:]) == word1: \n                return True\n        return False\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        # sort by length\n        # add smallest set to dictionary that maps the word to the longest length \n        # should be 1 to start with\n        # then go bigger looking @ smaller word list, compute longest length for each word\n        wordLengths = {}\n        for word in words:\n            if len(word) in wordLengths: \n                wordLengths[len(word)].append(word)\n            else: \n                wordLengths[len(word)] = [word]\n        longestStrChains = {}\n        totalMaxLength = 1\n        for length in sorted(wordLengths.keys()): \n            for word in wordLengths[length]: \n                if len(word) - 1 not in wordLengths: \n                    longestStrChains[word] = 1\n                else: \n                    maxLength = 1\n                    for smallerWord in wordLengths[len(word) - 1]: \n                        if self.isPredecessor(smallerWord, word): \n                            if maxLength < longestStrChains[smallerWord] + 1: \n                                maxLength = longestStrChains[smallerWord] + 1\n                    longestStrChains[word] = maxLength\n                    if totalMaxLength < maxLength: \n                        totalMaxLength = maxLength\n        print(wordLengths)\n        print(longestStrChains)\n        return totalMaxLength\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return\n        \n        dic = {}\n        result = 1\n        \n        for word in sorted(words, key=len):\n            dic[word] = 1\n            \n            for i in range(len(word)):\n                currWord = word[:i] + word[i+1:]\n                \n                if currWord in dic:\n                    dic[word] = max(dic[word], dic[currWord] + 1)\n                    result = max(result, dic[word])\n                    \n                    \n        return result\n                    \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def dfs(w1, size):\n            return max([dfs(w2, size + 1) for w2 in graph[w1]], default = size)\n        graph = collections.defaultdict(list)\n        for w in words:\n            graph[len(w)].append(w)\n        for w1 in words:\n            for w2 in graph[len(w1) + 1]:\n                for i in range(len(w2)):\n                    if w2[:i] + w2[i + 1:] == w1:\n                        graph[w1].append(w2)\n        return max(dfs(w, 1) for w in words)", "class Solution:\n    def isPredecessor(self, word1, word2): \n        for i in range(1, len(word2) + 1): \n            if (word2[:i-1] + word2[i:]) == word1: \n                return True\n        return False\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        # sort by length\n        # add smallest set to dictionary that maps the word to the longest length \n        # should be 1 to start with\n        # then go bigger looking @ smaller word list, compute longest length for each word\n        wordLengths = {}\n        for word in words:\n            if len(word) in wordLengths: \n                wordLengths[len(word)].append(word)\n            else: \n                wordLengths[len(word)] = [word]\n        longestStrChains = {}\n        totalMaxLength = 1\n        for length in sorted(wordLengths.keys()): \n            for word in wordLengths[length]: \n                if len(word) - 1 not in wordLengths: \n                    longestStrChains[word] = 1\n                else: \n                    maxLength = 1\n                    for smallerWord in wordLengths[len(word) - 1]: \n                        if self.isPredecessor(smallerWord, word): \n                            if maxLength < longestStrChains[smallerWord] + 1: \n                                maxLength = longestStrChains[smallerWord] + 1\n                    longestStrChains[word] = maxLength\n                    if totalMaxLength < maxLength: \n                        totalMaxLength = maxLength\n        return totalMaxLength\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        graph = collections.defaultdict(list)\n        maxlen = float('-inf')\n        minlen = float('inf')\n        for word in words:\n            graph[len(word)].append(word)\n            maxlen = max(maxlen, len(word))\n            minlen = min(minlen, len(word))\n        \n        # print(graph, minlen, maxlen)\n        \n        memo = {}\n        def predecessor(word1, word2):\n            if not word1:\n                return True\n            if len(word1)+1 != len(word2):\n                return False\n            if (word1, word2) in memo:\n                return memo[(word1, word2)]\n            fill = 1\n            left, right = 0 ,0 \n            ans = True\n            while left < len(word1) and right < len(word2):\n                if word1[left] != word2[right]:\n                    if fill:\n                        right += 1\n                        fill -= 1\n                        continue\n                    else:\n                        ans = False\n                        break\n                left += 1\n                right += 1\n            # print(word1, word2, True)\n            memo[(word1, word2)] = ans\n            return ans\n            \n        def chain(length, s=''):\n            if length not in graph:\n                return 0\n            ans = 0\n            for w in graph[length]:\n                if predecessor(s, w):\n                    ans = max(ans, 1 + chain(length+1, w))\n            return ans\n        \n        return max(chain(l) for l in range(minlen, maxlen+1))\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        dp = [1]*len(words)\n        \n        possible_pred = [0]*len(words)\n        for i in range(len(words)-1, -1, -1):\n            cur_word = words[i]\n            cur_length = len(cur_word)\n            for j in range(i+1, len(words)):\n                if len(words[j]) == cur_length+1 and cur_word in possible_pred[j]:\n                    dp[i] = max(dp[i], dp[j]+1)\n            pred = set()\n            for k in range(len(cur_word)):\n                pred.add(cur_word[0:k]+cur_word[k+1:])\n            possible_pred[i] = pred\n        return max(dp)\n                    \n", "class Solution:\n    def checkPredecessor(self, word_1, word_2):\n        find_extra = False\n        for i in range(len(word_1)):\n            chr_1 = word_1[i]\n            if not find_extra:\n                chr_2 = word_2[i]\n            else:\n                chr_2 = word_2[i + 1]\n            if chr_1 != chr_2:\n                if find_extra:\n                    return False\n                else:\n                    if chr_1 != word_2[i + 1]:\n                        return False\n                    find_extra = True\n        return True\n            \n    \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        longest_seq = [1] * len(words)\n        for i in range(1, len(words)):\n            curr_word = words[i]\n            for j in range(0, i)[::-1]:\n                prev_word = words[j]   \n                if len(prev_word) == len(curr_word):\n                    continue\n                if len(prev_word) + 1 < len(curr_word):\n                    break\n                if self.checkPredecessor(prev_word, curr_word):\n                    longest_seq[i] = max(longest_seq[i], longest_seq[j] + 1)\n        return max(longest_seq)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        \n        result = 1\n        \n        \n        for word in sorted(words,key=len):\n            dp[word] = 1\n            \n            for i in range(len(word)):\n                preword = word[:i]+word[i+1:]\n                if preword in dp:\n                    dp[word] = max(dp[preword]+1,dp[word])\n                    result = max(result, dp[word])\n        \n        return result", "# https://leetcode.com/problems/longest-string-chain/discuss/295008/Python-graph-DFS\nimport collections\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        self.graph = collections.defaultdict(list)\n        \n        for word in words:\n            self.graph[len(word)].append(word)\n            \n        for word1 in words:\n            for word2 in self.graph[len(word1)+1]:\n                for i in range(len(word2)):\n                    if word2[:i] + word2[i + 1:] == word1:\n                        self.graph[word1].append(word2)\n        \n    \n        return max(self.dfs(w, 1) for w in words)\n    \n    def dfs(self, word1, size):\n        return max([self.dfs(word2, size + 1) for word2 in self.graph[word1]], default = size)\n\n            \n        \n            \n            \n                \n                    \n        \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPredecessor(s1,s2):\n            add = False\n            s1_inx = 0\n            s2_inx = 0\n            while s1_inx < len(s1) and s2_inx < len(s2):\n                if s1[s1_inx] == s2[s2_inx]:\n                    s1_inx += 1\n                    s2_inx += 1\n                elif add == False:\n                    s2_inx += 1\n                    add = True\n                else:\n                    return False\n            return True\n        words = sorted(words, key = lambda x: len(x))\n        dp = [1] * len(words)\n        res = 1\n        for i in range(len(words)):\n            for j in range(0,i):\n                if len(words[i]) == len(words[j]):\n                    break\n                elif len(words[i]) - 1 > len(words[j]):\n                    continue\n                else:\n                    if isPredecessor(words[j],words[i]):\n                        dp[i] = max(dp[i],dp[j]+1)\n                        res = max(res,dp[i])\n        return res\n#         def isPre(word1,word2):\n#             flag=False\n#             indx1=0\n#             indx2=0\n#             while indx1 < len(word1) and indx2 < len(word2):\n#                 if word1[indx1] == word2[indx2]:\n#                     indx1 +=1\n#                     indx2+=1\n#                 elif flag == False:\n#                     indx2 +=1\n#                     flag =True\n#                 else:\n#                     return False\n#             return True\n        \n#         dp=len(words)*[1]\n#         words = sorted(words, key = lambda x: len(x))\n#         res=1\n#         for i in range(len(words)):\n#             for j in range(i):\n#                 if len(words[i])==len(words[j]):\n#                     break\n#                 elif len(words[i]) > len(words[j])+1:\n#                     continue\n#                 else:\n#                     if isPre(words[j],words[i]):\n#                         print(i)\n#                         dp[i]=max(dp[i],dp[j+1])\n#                         res=max(res,dp[i])\n       \n    \n", "class Solution:\n    def plusOne(self, a, b):\n        bigger = max([a, b], key=len)\n        smaller = min([a, b], key=len)\n        for i in range(len(bigger)):\n            if bigger[:i] + bigger[i+1:] == smaller:\n                return True\n        return False\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        memo = {}\n        sort = [[i for i in words if len(i) == a] for a in set([len(j) for j in words])][::-1]\n        print(sort)\n        for i, row in enumerate(sort):\n            if i == 0:\n                for j in row:\n                    memo[j] = 1\n            else:\n                for a in row:\n                    values = []\n                    for b in sort[i-1]:\n                        if self.plusOne(a, b):\n                            print((a, b))\n                            values.append(1 + memo[b])\n                    memo[a] = max(values) if values else 1 \n#         for key, value in memo.items(): \n#             print(key, value)\n        return max(memo.values())\n                        \n        \n            \n            \n    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        n = len(words)\n        dp = [1] * n\n        for i in range(n):\n            for j in reversed(list(range(i))):\n                if len(words[i]) == len(words[j]):\n                    continue\n                elif len(words[i]) > len(words[j]) + 1:\n                    break\n                \n                if self.helper(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n        \n        return max(dp)\n    \n    def helper(self, w1, w2):\n        # check if w1 is a predecessor of w2\n        i = 0\n        while i < len(w1) and w1[i] == w2[i]:\n            i += 1\n        \n        while i < len(w1) and w1[i] == w2[i + 1]:\n            i += 1\n        \n        return i == len(w1)\n", "from collections import defaultdict\nfrom queue import Queue\n\nclass Solution:\n    def is_pred(self, w1, w2):\n        for i in range(len(w2)):\n            if w2[:i] + w2[i+1:] == w1:\n                return True\n        return False\n            \n    def longestStrChain(self, words: List[str]) -> int:\n        graph = defaultdict(list)\n        words_by_len = defaultdict(list)\n        for word in words:\n            n = len(word)\n            words_by_len[n].append(word)\n        \n        roots = set(words)\n        for word in words:\n            possible_preds = words_by_len[len(word)-1]\n            for pred in possible_preds:\n                if self.is_pred(pred, word):\n                    graph[pred].append(word)\n                    if word in roots:\n                        roots.remove(word)\n        \n        max_depth = 1\n        for root in roots:\n            q = Queue()\n            q.put((root, 1))\n            while not q.empty():\n                curr, depth = q.get()\n                max_depth = max(max_depth, depth)\n                descs = graph[curr]\n                for desc in descs:\n                    q.put((desc, depth+1))\n        return max_depth\n            \n            \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def predecessor(word1, word2):\n            for i in range(len(word2)):\n                if word2[0:i] + word2[i + 1:] == word1:\n                    return True\n            return False\n        words.sort(key = len)\n        words_sort = {}\n        for i in words:\n            if len(i) in words_sort:\n                words_sort[len(i)].append(i)\n            else:\n                words_sort[len(i)] = [i]\n        def dfs(words, words_sort):\n            max_chain = 1\n            stack = [(1, word) for word in words[::-1]]\n            while stack:\n                current = stack.pop()\n                if current[0] > max_chain:\n                    max_chain = current[0]\n                if len(current[1]) + 1 in words_sort:\n                    for word in words_sort[len(current[1]) + 1]:\n                        if predecessor(current[1], word):\n                            if (1, word) in stack:\n                                stack.remove((1, word))\n                            stack.append((current[0] + 1, word))\n                else:\n                    continue\n            return max_chain\n        max_chain = dfs(words, words_sort)\n        return max_chain\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        m = collections.defaultdict(list)\n        words = sorted(words, key=len)\n        for w in words:\n            m[len(w)].append(''.join(sorted(w)))\n            \n        if len(m) == 1:\n            return 1\n        \n        def equal(x, y):\n            for i in range(len(x)):\n                if x[i] != y[i]:\n                    return x == (y[:i] + y[i+1:])\n            return True\n        \n        def dfs(w):\n            k = len(w) + 1\n            if k not in m:\n                return 0\n            return max([dfs(x) + 1 for x in m[k] if equal(w, x)] or [0])\n        \n        return max(dfs(x) for y in list(m.keys())[:-1] for x in m[y]) + 1\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x: len(x))                      # words from short to long \n        counter = {}                                            \n        minLen = len(words[0])                                  # minimum length of word\n        maxLen = 1\n        for idx in range(len(words)):\n            if len(words[idx]) == minLen:\n                counter[idx] = 1                                # base case \n            else:\n                ancestor = 1\n                j = 0 \n                while idx - j >= 0 and len(words[idx-j]) >= len(words[idx]) - 1:\n                    j += 1\n                    if len(words[idx-j]) == len(words[idx]):    # do not check words with the same length \n                        continue \n                    if self.checker(words[idx-j], words[idx]):       # check if words[idx-j] is an ancestor of words[idx]\n                        #print(words[idx-j], words[idx])\n                        ancestor = max(ancestor, counter[idx-j] + 1)\n                counter[idx] = ancestor \n                maxLen = max(maxLen, ancestor)\n        return maxLen\n     \n    \n    def checker(self, short, long):\n        for idx in range(len(long)):\n            removed = long[0:idx] + long[idx+1:]\n            if short == removed:\n                return True \n        return False ", "class Solution:\n    def IsPredecessor(self, w1, w2):\n        # return true if w2 is predecessor of w1\n        if len(w1)+1 != len(w2):\n            return False\n        if len(w1)==0:\n            return True  \n\n        diff = 0\n        for i in range(len(w2)):\n            if i-diff==len(w1) or w1[i-diff] != w2[i]:\n                diff += 1\n\n        return diff==1\n        \n    def longestStrChain(self, words: List[str]) -> int:\n         \n        if len(words)<1:\n            return 0\n        \n        # Use a hashmap to record the length and the index\n        length_position = [[] for i in range(17)]\n        for i in range(len(words)):\n            w = words[i]\n            length_position[len(w)].append(i)\n                  \n        dp = [1]*len(words)\n        \n        # visit the dictionaty from shorter length to longer length\n        for i in range(2, 17):\n            if len(length_position[i-1])==0 or len(length_position[i])==0:\n                continue\n            current = length_position[i]\n            previous = length_position[i-1]\n            for j in current:\n                for k in previous:\n                    if self.IsPredecessor(words[k], words[j]):\n                        dp[j] = max(dp[j], dp[k]+1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n    \n    \n        size = 0\n        wordSet = set(words)\n        mem = {}\n        \n        def dfs(s):\n\n            if s in mem:\n                return mem[s]\n            \n            maxpath = 1\n            for i in range(len(s)):\n                new = s[:i] + s[i+1:]\n                if new in wordSet:\n                    maxpath = max(maxpath, 1+dfs(new))\n            \n            mem[s] = maxpath\n\n            return mem[s]\n        \n        \n        for word in words:\n            if word not in mem:\n                size = max(size, dfs(word))\n        print(mem)\n        return size\n        \n        \n        \n        dic=collections.defaultdict(int)\n        words=sorted(words,key=lambda x:len(x))\n        for word in words:\n            dic[word]=1\n            for i in range(len(word)):\n                tmp=word[:i]+word[i+1:]\n                if tmp in dic:\n                    dic[word]=max(dic[word],dic[tmp]+1)\n                    \n        return max(dic.values())\n    \n        \n        \n        \n        \n        \n                    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n\n        # key is current word, value is current length\n        chains = {}\n        len_arr = [len(x) for x in words]\n        min_len, max_len = min(len_arr), max(len_arr)\n        max_len_w = [w for w in words if len(w) == max_len]\n        for w in max_len_w:\n            chains[w] = 1\n        \n        for length in range(max_len-1, min_len-1, -1):\n            for w in words:\n                if len(w) != length:\n                    continue\n                max_w = 1\n                for key in chains:\n                    if len(key) == len(w) + 1 and self.is_chain(w, key):\n                        max_w = max(max_w, chains[key] + 1)\n                chains[w] = max_w\n        len_chain = [y for x,y in list(chains.items())]\n        return max(len_chain)\n    \n    def is_chain(self, small_w, large_w):\n        for i in range(len(large_w)):\n            if large_w[:i] + large_w[i+1:] == small_w:\n                return True\n        return False\n                        \n                        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        graph = collections.defaultdict(list)\n        maxlen = float('-inf')\n        minlen = float('inf')\n        for word in words:\n            graph[len(word)].append(word)\n            maxlen = max(maxlen, len(word))\n            minlen = min(minlen, len(word))\n        \n        # print(graph, minlen, maxlen)\n        \n        def predecessor(word1, word2):\n            if not word1:\n                return True\n            if len(word1)+1 != len(word2):\n                return False\n            fill = 1\n            left, right = 0 ,0 \n            while left < len(word1) and right < len(word2):\n                if word1[left] != word2[right]:\n                    if fill:\n                        right += 1\n                        fill -= 1\n                        continue\n                    else:\n                        return False\n                left += 1\n                right += 1\n            # print(word1, word2, True)\n            return True\n            \n        def chain(length, s=''):\n            if length not in graph:\n                return 0\n            ans = 0\n            for w in graph[length]:\n                if predecessor(s, w):\n                    ans = max(ans, 1 + chain(length+1, w))\n            return ans\n        \n        return max(chain(l) for l in range(minlen, maxlen+1))\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        words_dict ={}\n        for word in words:\n            dp[word] = -1\n            if words_dict.get(len(word)):\n                words_dict[len(word)].append(word)\n            else:\n                words_dict[len(word)] = [word]\n        result = 0\n        for word in words:\n            result = max(result, self.longest_chain(word, dp, words_dict))\n        return result\n            \n    def longest_chain(self, word, dp, words_dict):\n        if dp[word]!=-1:\n            return dp[word]\n        if not words_dict.get(len(word)+1):\n            return 1\n        res = 0\n        for word2 in words_dict[len(word)+1]:\n            if self.isSucc(word, word2):\n                res = max(res, self.longest_chain(word2, dp, words_dict))\n        res +=1\n        return res\n        \n    def isSucc(self, word1,word2):\n        \n        if len(word1)!=len(word2)-1:\n            return False\n        count=0\n        i=0\n        j=0\n        while i<len(word1):\n            if word1[i]!=word2[j]:\n                if count==1:\n                    return False\n                count+=1\n                j+=1\n            else:\n                j+=1\n                i+=1\n            \n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x:len(x))\n        chainLen = {w:1 for w in words}\n        ret = 1\n        for i, word1 in enumerate(words):\n            for j in range(i+1, len(words)):\n                word2 = words[j]\n                if len(word2) == len(word1):\n                    continue\n                if len(word2) > len(word1) + 1:\n                    break\n                insert = False\n                match = True\n                idx1 = 0\n                idx2 = 0\n                while idx1 < len(word1):\n                    if word1[idx1] != word2[idx2]:\n                        if insert:\n                            match = False\n                            break\n                        else:\n                            insert = True\n                            idx2 += 1\n                            continue\n                    idx1 += 1\n                    idx2 += 1\n                if match:\n                    l = max(chainLen[word2], chainLen[word1] + 1)\n                    ret = max(ret, l)\n                    chainLen[word2] = l\n        return ret\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        table = defaultdict(list)\n        for w in words:\n            table[len(w)].append(w)\n        max_len = max(len(w) for w in words)\n            \n        \n        def backtracking(cur, n):\n            if len(cur) == max_len:\n                return 0\n            if not cur in dp:\n                res = 0\n                for word in table[n]:\n                    for i in range(len(word)):\n                        if word[0:i] + word[i + 1:] == cur:\n                            res = max(res, backtracking(word, n + 1) + 1)\n                            break\n                dp[cur] = res\n            return dp[cur]\n        \n        res = 0\n        for i, v in table.items():\n            for w in v:\n                res = max(res, backtracking(w, i + 1) + 1)\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = list(set(words))\n        words = sorted(words, key=lambda x: len(x))\n        \n        # key is current word, value is current length\n        chains = {}\n        len_arr = [len(x) for x in words]\n        min_len, max_len = min(len_arr), max(len_arr)\n        max_len_w = [w for w in words if len(w) == max_len]\n        for w in max_len_w:\n            chains[w] = 1\n        \n        for length in range(max_len-1, min_len-1, -1):\n            for w in words:\n                if len(w) != length:\n                    continue\n                max_w = 1\n                for key in chains:\n                    if len(key) == len(w) + 1 and self.is_chain(w, key):\n                        max_w = max(max_w, chains[key] + 1)\n                chains[w] = max_w\n                        \n        len_chain = [y for x,y in list(chains.items())]\n        return max(len_chain)\n    \n    def is_chain(self, small_w, large_w):\n        for i in range(len(large_w)):\n            if large_w[:i] + large_w[i+1:] == small_w:\n                return True\n        return False\n                        \n                        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        graph = collections.defaultdict(list)\n        maxlen = float('-inf')\n        minlen = float('inf')\n        for word in words:\n            graph[len(word)].append(word)\n            maxlen = max(maxlen, len(word))\n            minlen = min(minlen, len(word))\n        \n        # print(graph, minlen, maxlen)\n        \n        def predecessor(word1, word2):\n            if not word1:\n                return True\n            if len(word1)+1 != len(word2):\n                return False\n            fill = 1\n            left, right = 0 ,0 \n            while left < len(word1) and right < len(word2):\n                if word1[left] != word2[right]:\n                    if fill:\n                        right += 1\n                        fill -= 1\n                        continue\n                    else:\n                        return False\n                left += 1\n                right += 1\n            # print(word1, word2, True)\n            return True\n            \n        def chain(length, s=''):\n            if length not in graph:\n                return 0\n            ans = 0\n            for w in graph[length]:\n                if predecessor(s, w):\n                    ans = max(ans, 1 + chain(length+1, w))\n            return ans\n        \n        ans = 1\n        # for l in range(minlen, maxlen+1):\n        #     for w in graph[l]:\n        #         res = chain(l+1, w) +1 \n        #         # print(res)\n        #         ans = max(ans, res)\n        return max(chain(l) for l in range(minlen, maxlen+1))\n", "class Solution:\n    def get_dict(self, word):\n        d = {}\n        for c in word:\n            d[c] = d.get(c, 0) + 1\n        return d\n    \n    def is_close(self, word1, word2):\n        dict_word1 = self.get_dict(word1)\n        dict_word2 = self.get_dict(word2)\n        diff = False\n        \n        for letter, freq in list(dict_word2.items()):\n            if letter in dict_word1:\n                if abs(freq - dict_word1[letter]) == 1:\n                    if not diff:\n                        diff = True\n                    else:\n                        return False\n                elif abs(freq - dict_word1[letter]) > 1:\n                    return False\n            else:\n                if freq > 1:\n                    return False\n                else:\n                    if not diff:\n                        diff = True\n                    else:\n                        return False\n        return True\n         \n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        dict_lens = {}\n        dict_words = {}\n        \n        for word in words:\n            dict_lens.setdefault(len(word), []).append(word)\n            dict_words[word] = 0\n            \n        max_res = 0\n        sorted_keys = sorted(dict_lens.keys())\n        for len_num in sorted_keys:\n            if len_num + 1 in dict_lens:\n                next_word_list = dict_lens[len_num + 1]\n            else:\n                continue\n            \n            for word in dict_lens[len_num]:\n                for next_word in next_word_list:\n                    if self.is_close(word, next_word):\n                        dict_words[next_word] = max(dict_words[next_word], dict_words[word]+1)\n                        max_res = max(max_res, dict_words[next_word])\n        \n        return max_res + 1\n                    \n                    \n                    \n                    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n    \n    \n        size = 0\n        wordSet = set(words)\n        mem = {}\n        \n        def dfs(s):\n\n            if not s:\n                return 1\n            \n            if s in mem:\n                return mem[s]\n            \n            maxpath = 1\n            for i in range(len(s)):\n                new = s[:i] + s[i+1:]\n                if new in wordSet:\n                    maxpath = max(maxpath, 1+dfs(new))\n            \n            mem[s] = maxpath\n\n            return mem[s]\n        \n        \n        for word in words:\n            if word not in mem:\n                size = max(size, dfs(word))\n        print(mem)\n        return size\n        \n        \n        \n        dic=collections.defaultdict(int)\n        words=sorted(words,key=lambda x:len(x))\n        for word in words:\n            dic[word]=1\n            for i in range(len(word)):\n                tmp=word[:i]+word[i+1:]\n                if tmp in dic:\n                    dic[word]=max(dic[word],dic[tmp]+1)\n                    \n        return max(dic.values())\n    \n        \n        \n        \n        \n        \n                    \n", "class Solution:\n    def IsPredecessor(self, w1, w2):\n        # return true if w2 is predecessor of w1\n        if len(w1)+1 != len(w2):\n            return False\n        if len(w1)==0:\n            return True  \n\n        diff = 0\n        for i in range(len(w2)):\n            if i-diff==len(w1) or w1[i-diff] != w2[i]:\n                diff += 1\n\n        return diff==1\n        \n    def longestStrChain(self, words: List[str]) -> int:\n         \n        if len(words)<1:\n            return 0\n        \n        # Use a hashmap to record the length and the index\n        length_position = {}\n        for i in range(len(words)):\n            w = words[i]\n            if len(w) in length_position:\n                length_position[len(w)].append(i)\n            else:\n                length_position[len(w)] = [i]\n                  \n        dp = [1]*len(words)\n        # visit the dictionaty from shorter length to longer length\n        for i in sorted(length_position):\n            if (i-1) not in length_position:\n                continue\n            current = length_position[i]\n            previous = length_position[i-1]\n            for j in current:\n                for k in previous:\n                    if self.IsPredecessor(words[k], words[j]):\n                        dp[j] = max(dp[j], dp[k]+1)\n                \n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        contains = lambda w1, w2: all(l1 in w2 for l1 in w1)\n        \n        words.sort(key=lambda a: len(a))\n        n = len(words)\n        chain = [1] * n\n        for i in range(n):\n            j = i+1\n            while j < n and len(words[j]) == len(words[i]):\n                j += 1\n            while j < n and len(words[j]) == len(words[i]) + 1:\n                if contains(words[i], words[j]) and chain[i] + 1 > chain[j]:\n                    chain[j] = chain[i] + 1\n                j += 1\n        \n        return max(chain)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        d = {}\n        for word in words:\n            if len(word) in d:\n                d[len(word)].append(word)\n            else:\n                d[len(word)] = [word]\n        visited = {}\n        res = 0\n        for word in sorted(words):\n            res = max(res, self.dfs(word, visited, d))\n        return res\n        \n    def checkPredecessor(self, word1, word2):\n        return any(word1 == word2[:i] + word2[i + 1:] for i in range(len(word2)))\n    \n    def dfs(self, word, visited, d):\n        if word in visited:\n            return visited[word]\n        if len(word) + 1 not in d:\n            visited[word] = 1\n            return 1\n        res = 1\n        for w in d[len(word) + 1]:\n            if self.checkPredecessor(word, w):\n                res = max(res, self.dfs(w, visited, d) + 1)\n        visited[word] = res\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        W = defaultdict(list)\n        for i,w in enumerate(words):\n            W[len(w)].append(i)\n        #print(W)\n        G = defaultdict(set)\n        for i in range(n):\n            for j in W[len(words[i])+1]:\n                found = False\n                for k in range(len(words[j])):\n                    if words[i]==words[j][:k]+words[j][k+1:]:\n                        found = True\n                        break\n                if found:\n                    G[i].add(j)\n        #print(G)\n        @lru_cache(None)\n        def dfs(i):\n            out = 1\n            for j in G[i]:\n                out = max(out,1+dfs(j))\n            return out\n        return max(dfs(i) for i in range(n))\n    \n                    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        dicti = collections.defaultdict(set)\n        for word in words:\n            dicti[len(word)].add(word)\n            \n        chars = [chr(i) for i in range(ord('a'), ord('z')+1)]\n        memo = {}\n        \n        def dist(word):\n            if word in memo:\n                return memo[word]\n            if len(word)+1 not in dicti:\n                memo[word] = 1\n                return memo[word]                \n\n            n = len(word)\n            ans = 0\n            for ch in chars:\n                for i in range(n+1):\n                    new_word = word[:i] + ch + word[i:]\n                    if  new_word in dicti[n+1]:\n                        ans = max(ans, dist(new_word))\n                        \n            memo[word] = ans + 1\n            return ans + 1\n        \n        ans = 0\n        for word in words:\n            ans = max(ans, dist(word))\n        return ans\n        \n        \n                \n\n                    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = [1 for _ in range(len(words)+1)] ## length of word chain\n        dp[0] = 0 \n        words = sorted(words, key=lambda x:len(x))\n        hmap = collections.defaultdict(list) #{length: words}\n        for i, word in enumerate(words):\n            hmap[len(word)] += [(word, i)]\n        \n        for i in range(1, len(words)+1):\n            key = len(words[i-1])-1\n            for word, idx in hmap[key]:\n                ## if word is predecessor of words[i]\n                ## , then dp[i] = max(dp[i], dp[idx+1])\n                if self.predecessor(word, words[i-1]):\n                    dp[i] = max(dp[i], dp[idx+1]+1)\n        \n        return max(dp)\n    \n    def predecessor(self, word0, word1):\n        cnt0 = collections.Counter(word0)\n        cnt1 = collections.Counter(word1)\n        for key in cnt0:\n            if key not in cnt1:\n                return False\n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) <= 0:\n            return 0\n        \n        words.sort(key=len)\n        numberOfWords = len(words)\n        longestLens = [1] * len(words)\n        index = numberOfWords - 1\n        while index >= 0:\n            if index == 0 or len(words[index]) != len (words[index - 1]):\n                index -= 1\n                break\n            index -= 1\n        \n        while index >= 0:\n            maxLen = 1\n            index2 = index + 1\n            while index2 < numberOfWords and len(words[index]) + 1 >= len(words[index2]):\n                if self.isPredecessor(words[index], words[index2]):\n                    if maxLen < longestLens[index2] + 1:\n                        maxLen = longestLens[index2] + 1\n                index2 += 1\n            longestLens[index] = maxLen\n            index -= 1\n        \n        maxLen = longestLens[0]\n        for longestLen in longestLens:\n            if maxLen < longestLen:\n                maxLen = longestLen\n        return maxLen\n                    \n    \n    def isPredecessor(self, word1:str, word2:str)-> bool:\n        if len(word2) - len(word1) != 1:\n            return False\n        for i, ch in enumerate(word2):\n            newWord = word2[:i] + word2[i+1:]\n            if newWord == word1:\n                return True\n        return False\n    \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        for w in sorted(words, key=len):\n            dp[w] = max(dp.get(w[:i] + w[i + 1:], 0) + 1 for i in range(len(w)))\n        return max(dp.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n=len(words)\n        a=sorted(words,key=len)\n        dp=[1]*n\n        def helper(a1,b1):\n            s=0\n           \n            n=len(b1)\n            i=0\n            j=0\n            while(i<n and j<n+1):\n                if a1[j]==b1[i]:\n                    i+=1\n                    j+=1\n                elif a1[j]!=b1[i] and s==0:\n                    s+=1\n                    j+=1\n                else:\n                    return 0\n            return 1    \n                    \n        \n        for i in range(1,n):\n            for j in range(i-1,-1,-1):\n                if len(a[j])==len(a[i]):\n                    continue\n                elif len(a[j])<len(a[i])-1:\n                    break\n                x=helper(a[i],a[j])\n                if x==1:\n                    dp[i]=max(dp[i],dp[j]+1)\n        return max(dp)            ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        m = collections.defaultdict(list)\n        \n        for w in words:\n            m[len(w)].append(w)\n            \n        if len(m) == 1:\n            return 1\n        \n        for k in list(m.keys()):\n            m[k] = [''.join(sorted(x)) for x in m[k]]\n        \n        def equal(x, y):\n            for i in range(len(x)):\n                if x[i] != y[i]:\n                    return x == (y[:i] + y[i+1:])\n            return True\n        \n        def dfs(w):\n            k = len(w) + 1\n            if k not in m:\n                return 0\n            return max([dfs(x) + 1 for x in m[k] if equal(w, x)] or [0])\n        \n        return max(dfs(x) for y in sorted(list(m.keys()))[:-1] for x in m[y]) + 1\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # sort by decreasing length\n        # define vector L of length len(words) such that it's the longest \n        # word chain starting from that word\n        # then recuriosn is L_k = 1 if it is not predecessor of any 1 longer words\n        # otherwise it is 1 + max L_j for j such that k is predecessor of them\n        \n        lengths = [len(word) for word in words]\n        wordsSorted = [x for _,x in sorted(zip(lengths,words),reverse = True)]\n        \n        print(wordsSorted)\n        L = [1]*len(wordsSorted)\n        maxLength = max(lengths)\n        for k in range(0, len(L)):\n            lenWord = len(wordsSorted[k])\n            for l in range(k):\n                if len(wordsSorted[l]) == lenWord+1 and (set(wordsSorted[l]) & set(wordsSorted[k])) == set(wordsSorted[k]):\n                    L[k] = max(L[k], 1 + L[l])\n        return(max(L))\n                    \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        from collections import defaultdict\n        \n        d = {}\n        for word in words:\n            if len(word) in d:\n                d[len(word)].append(word)\n            else:\n                d[len(word)] = [word]\n        def isPred(w1, w2):\n            for i in range(len(w2)):\n                if w2[:i] + w2[i+1:] == w1:\n                    return True\n            return False\n        \n        followers = defaultdict(list)\n        for word in words:\n            if len(word) +1 in d:\n                for biggerWord in d[len(word)+1]:\n                    if isPred(word, biggerWord):\n                        followers[word].append(biggerWord)\n        \n        self.maxDist = 1\n        def dfs(start, dist, found = set()):\n            found.add(start)\n            for neighbor in followers[start]:\n                if neighbor not in found:\n                    self.maxDist = max(self.maxDist, dist + 1)\n                    dfs(neighbor, dist + 1, found)\n        \n        keys = [key for key in followers]\n        for key in keys:\n            s = set()\n            dfs(key, 1, set())\n            \n        return self.maxDist\n", "class Solution:\n    # sort from smallest to largest length\n    # for each element, see if any words of its length - 1 are predescessors\n    # for every predecessor, take the max of the word chains and store it + 1\n    def isPredecessor(self, prev_word, cur_word):\n        if len(prev_word) != len(cur_word) - 1:\n            return False\n        skipped_char = False\n        for i in range(len(prev_word)):\n            if not skipped_char and prev_word[i] != cur_word[i]:\n                skipped_char = True\n            if skipped_char and prev_word[i] != cur_word[i+1]:\n                return False\n        return True\n\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda word: len(word))\n        num_words = len(words)\n        chain_lengths = [1 for _ in range(num_words)]\n        max_chain_length = 0\n        for i in range(num_words):\n            for j in range(0, i):\n                if len(words[j]) == len(words[i]) - 1 and chain_lengths[j] + 1 > chain_lengths[i] and self.isPredecessor(words[j], words[i]):\n                    chain_lengths[i] = chain_lengths[j] + 1\n            max_chain_length = max(max_chain_length, chain_lengths[i])\n        return max_chain_length\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPred(w1,w2):\n            i,j = 0, 0\n            while i < len(w1):\n                if w1[i] != w2[j]:\n                    if j != i:\n                        return False\n                    j += 1\n                else:\n                    j += 1\n                    i += 1\n            return True\n\n        words = sorted(words, key=lambda x:len(x))\n        dp = [1]*len(words)\n        for i in range(1,len(words)):\n            for j in range(i):\n                if len(words[i])==(len(words[j])+1) and isPred(words[j],words[i]):\n                    dp[i] = max(dp[i],dp[j]+1)\n         \n        return max(dp)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n=len(words)\n        for ele in words:\n            ele=list(ele)\n        words = sorted(words, key = lambda x: len(x))\n        #print(words)\n        arr=[1]*n\n        for i in range(1,n):\n            for j in range(0,i):\n                if len(words[j])==len(words[i])-1:\n                    if(all(x in words[i] for x in words[j])): \n                        arr[i]=max(arr[i],arr[j]+1)\n                        #print(words[i],words[j])\n                #print(words[i],words[j])\n        print(arr)\n        return max(arr)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        by_length = collections.defaultdict(set)\n        for word in words:\n            by_length[len(word)].add(word)\n\n        longest = 1\n        seen = {*()} # set()\n        mx = len(by_length)\n        mn = min(by_length)\n        # in descending order\n        for length in sorted(by_length, reverse=True):\n           # if length - mn < longest:\n           #     break\n            for word in by_length[length]:\n                if length - mn < longest:\n                    break\n                if word in seen:\n                    continue\n                stk = [(word, length, 1)]\n                while stk:\n                    word, k, n = stk.pop()\n                    seen.add(word)\n                    if n > longest:\n                        longest = n\n                    for i in range(k):\n                        pre = word[:i] + word[i+1:]\n                        if pre not in seen and pre in by_length[k-1]:\n                            stk.append((pre, k-1, n+1))\n               # if longest == mx:\n               #     return longest\n\n        return longest   ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        for w in sorted(words, key=len):\n            # print()\n            # print(w)\n            temp = [dp.get(w[:i] + w[i + 1:], 0) + 1 for i in range(len(w))]\n            # print(temp)\n            dp[w] = max(temp)\n            # print(dp)\n        return max(dp.values())\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        auxList = [(len(item), item) for item in set(words)]\n        auxList.sort()\n        auxCntList = [1] * len(auxList)\n        ans = 1\n\n        for idx, (wordLen, word) in enumerate(auxList):\n            for jdx in range(idx+1, len(auxList)):\n                cWordLen, cWord = auxList[jdx]\n                if cWordLen > wordLen + 1:\n                    break\n                elif cWordLen == wordLen:\n                    pass\n                else:\n                    for pivot in range(len(cWord)):\n                        if cWord[:pivot] + cWord[pivot+1:] == word:\n                            auxCntList[jdx] = auxCntList[idx] + 1\n                            ans = max(ans, auxCntList[jdx])\n\n        return ans\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        wordsbylen = collections.defaultdict(list)\n        for w in words:\n            wordsbylen[len(w)].append(w)\n        \n        # @functools.lru_cache(None)\n        def get_longest_derivate(word):\n            potential = wordsbylen[len(word)+1]\n            possible = [1]\n            for p in potential:\n                i, j = 0, 0\n                while i < len(p) and j < len(word):\n                    if p[i] == word[j]:\n                        i += 1\n                        j += 1\n                    elif i != j:\n                        break\n                    else:\n                        i += 1\n                if j == len(word):\n                    possible.append(1 + get_longest_derivate(p))\n            return max(possible)\n        \n        return max(map(get_longest_derivate, words))", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        auxList = [(len(item), item) for item in set(words)]\n        auxList.sort()\n        \n        auxGraph = collections.defaultdict(set)\n        seen = dict()\n        \n        for idx, (wordLen, word) in enumerate(auxList):\n            seen[word] = False\n            for jdx in range(idx+1, len(auxList)):\n                cWordLen, cWord = auxList[jdx]\n                if cWordLen > wordLen + 1:\n                    break\n                elif cWordLen == wordLen:\n                    pass\n                else:\n                    for pivot in range(len(cWord)):\n                        if cWord[:pivot] + cWord[pivot+1:] == word:\n                            auxGraph[word].add(cWord)\n        # print(auxGraph)\n        ans = 0\n        auxDeque = collections.deque()\n        for _, word in auxList:\n            if seen[word]:\n                pass\n            else:\n                seen[word] = True\n                # DFS or BFS\n                auxDeque.append((1, word))\n                \n                while len(auxDeque) > 0:\n                    cLen, cnode = auxDeque.pop()\n                    ans = max(ans, cLen)\n                    for eachNeighbor in auxGraph[cnode]:\n                        if not seen[eachNeighbor]:\n                            seen[eachNeighbor] = True\n                            auxDeque.append((cLen + 1, eachNeighbor))\n        return ans\n", "from collections import Counter, defaultdict\n\nclass Solution:\n    def is_one_away(self, c_1, c_2) -> bool:\n        # c_1 will be shorter than c_2\n        diff = 0\n        for k, v in list(c_2.items()):\n            diff += v - c_1.get(k, 0)\n            if diff > 1:\n                return False\n        \n        for k in c_1:\n            if k not in c_2:\n                return False\n        \n        return True\n    \n    def helper(self, word, words_for_len, counters_for_words):\n        w_counter = counters_for_words[word]\n        max_chain = 0\n        for w in words_for_len[len(word) + 1]:\n            if self.is_one_away(w_counter, counters_for_words[w]):\n                max_chain = max(max_chain, self.helper(w, words_for_len, counters_for_words))\n        return max_chain + 1\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        # Logic:\n        # define the longest string chain starting at word w as L[w]\n        #   L[w] = 1 + max over all w' in W such that dist(w, w') == 1(L[w'])\n        # Compute map of length to word counters to easily find all words 1 letter increased from a given word\n        # Given some w,\n        #     max_chain := 0\n        #     For all w' one letter away\n        #          max_chain := max(max_chain, max_chain(w')) + 1\n        # return max_chain\n        # Time Complexity analysis: ??\n        # Space: recursive stack O(n) will be the depth of the tree, hashmap O(n)\n        words_for_len = defaultdict(list)\n        counters_for_words = {w: Counter(w) for w in words}\n        for w in words:\n            words_for_len[len(w)].append(w)\n        \n        max_chain = 0\n        for w in words:\n            max_chain = max(max_chain, self.helper(w, words_for_len, counters_for_words))\n        return max_chain\n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(w1, w2):\n            for i, w in enumerate(w1):\n                if(w != w2[i]):\n                    return w1[i:] == w2[i+1:]\n            \n            return True\n        \n        words.sort(key=len, reverse=True)\n        len_words = len(words)\n        combos = [0] * len_words\n        \n        for i in range(len_words):\n            for j in reversed(list(range(0, i))):\n                len_i, len_j = len(words[i]), len(words[j])\n                if(len_i + 1 < len_j):\n                    break\n                elif(len_i == len_j):\n                    continue\n                if(combos[i] < combos[j] + 1\n                   and is_predecessor(words[i], words[j])):\n                    combos[i] = combos[j] + 1\n        \n        return max(combos) + 1\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(w1, w2):\n            for i in range(len(w1)):\n                if(w1[i] != w2[i]):\n                    return w1[i:] == w2[i+1:]\n            \n            return True\n        \n        words.sort(key=len, reverse=True)\n        print(words)\n        len_words = len(words)\n        combos = [0] * len_words\n        \n        for i in range(len_words):\n            for j in reversed(list(range(0, i))):\n                len_i, len_j = len(words[i]), len(words[j])\n                if(len_i + 1 < len_j):\n                    break\n                if(len_i + 1 == len_j\n                   and combos[i] < combos[j] + 1\n                   and is_predecessor(words[i], words[j])):\n                    combos[i] = combos[j] + 1\n                    \n        # for i in range(len_words):\n        #     print(combos[i], end=', ')\n        #     print(words[i])\n        \n        \n        return max(combos) + 1\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        dp = [1]*len(words)\n        m = 1\n        for i in range(1, len(words)):\n            j = i-1\n            cl = len(words[i])\n            while(len(words[j]) >= cl-1 and j>-1):\n                if(len(words[j]) == cl):\n                    j-=1\n                    continue\n                f = 0\n                w1, w2 = words[i], words[j]\n                li, lj = 0,0\n                while(f<2 and lj < len(w2)):\n                    if(w1[li] == w2[lj]):\n                        li+=1\n                        lj+=1\n                    else:\n                        f+=1\n                        li+=1\n                if(f!=2):\n                    dp[i] = max(dp[i], 1 + dp[j])\n                    m = max(dp[i], m) \n                j-=1\n        return m  \n                   \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        for w in sorted(words, key=len):\n            dp[w] = max(dp.get(w[:i] + w[i + 1:], 0) + 1 for i in range(len(w)))\n        return max(dp.values())\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def compare(w1,w2):\n            i,j = 0, 0\n            while i < len(w1):\n                if w1[i] != w2[j]:\n                    if j != i:\n                        return False\n                    j += 1\n                else:\n                    j += 1\n                    i += 1\n            return True\n        \n        words = sorted(words, key=lambda x:len(x))\n        n = len(words)\n        dp = [1]*len(words)\n        for i in range(1,n):\n            for j in range(i):\n                if len(words[i])-len(words[j])==1:\n                    if compare(words[j],words[i]):\n                        dp[i] = max(dp[i],dp[j]+1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def check(str1, str2):\n            for i in range(len(str2)):\n                temp = str2[:i] + str2[i+1:]\n                if temp == str1:\n                    return True\n            return False\n        words.sort(key=len)\n        min_length = len(words[0])\n        dp = [1]*len(words)\n        \n        for i in range(len(words)):\n            if len(words[i]) == min_length:\n                continue\n            for j in range(len(words)):\n                if len(words[j]) == len(words[i]) - 1:\n                    if check(words[j], words[i]):\n                        dp[i] = max(dp[i], dp[j]+1)\n                elif len(words[j]) >= len(words[i]):\n                    break\n        return max(dp)\n                \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(w1, w2):\n            for i in range(len(w1)):\n                if(w1[i] != w2[i]):\n                    return w1[i:] == w2[i+1:]\n            \n            return True\n        \n        words.sort(key=len, reverse=True)\n        len_words = len(words)\n        combos = [0] * len_words\n        \n        for i in range(len_words):\n            for j in reversed(list(range(0, i))):\n                len_i, len_j = len(words[i]), len(words[j])\n                if(len_i + 1 < len_j):\n                    break\n                if(len_i + 1 == len_j\n                   and combos[i] < combos[j] + 1\n                   and is_predecessor(words[i], words[j])):\n                    combos[i] = combos[j] + 1\n                    \n        # for i in range(len_words):\n        #     print(combos[i], end=', ')\n        #     print(words[i])\n        \n        \n        return max(combos) + 1\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def contains(w1, w2):\n            return all(l1 in w2 for l1 in w1)\n        \n        words.sort(key=lambda a: len(a))\n        n = len(words)\n        chain = [1] * n\n        for i in range(n):\n            j = i+1\n            while j < n and len(words[j]) == len(words[i]):\n                j += 1\n            while j < n and len(words[j]) == len(words[i]) + 1:\n                if contains(words[i], words[j]) and chain[i] + 1 > chain[j]:\n                    chain[j] = chain[i] + 1\n                j += 1\n        \n        return max(chain)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(w1, w2):\n            for i in range(len(w1)):\n                if(w1[i] != w2[i]):\n                    return w1[i:] == w2[i+1:]\n            \n            return True\n        \n        words.sort(key=len, reverse=True)\n        combos = [0] * len(words)\n        \n        for i in range(len(words)):\n            for j in reversed(list(range(0, i))):\n                len_i, len_j = len(words[i]), len(words[j])\n                if(len_i + 1 < len_j):\n                    break\n                if(len_i + 1 == len_j\n                   and combos[i] < combos[j] + 1\n                   and is_predecessor(words[i], words[j])):\n                    combos[i] = combos[j] + 1\n\n        return max(combos) + 1\n", "    \ndef is_pre(s1, s2):\n    c = 0\n    i = 0\n    for j in range(len(s2)):\n        if i == len(s1) or s1[i] != s2[j]:\n            c += 1\n        else:\n            i += 1\n    return c == 1\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key= len)\n        n = len(words)\n        m = {}\n        incount = {}\n        q = collections.deque()\n        seen = set()\n        for i in range(n):\n            if i not in incount:\n                q.append(i)\n            wn = len(words[i])\n            for j in range(i+1, n):\n                jn = len(words[j])\n                if jn > wn + 1:\n                    break\n                if jn == wn + 1 and is_pre(words[i], words[j]):\n                    m.setdefault(i, []).append(j)\n                    incount[j] = incount.get(j, 0) + 1\n        lev = 0\n        while q:\n            lev += 1\n            for i in range(len(q)):\n                u = q.popleft()\n                for v in m.get(u, []):\n                    if v not in seen:\n                        q.append(v)\n                        seen.add(v)\n        return lev\n            \n            \n            \n            \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        chain = {}\n        for w in sorted(words, key=len):\n            weights = [chain.get(w[:i] + w[i + 1:], 0) + 1 for i in range(len(w))]\n            \n            chain[w] = max(weights)\n        return max(chain.values())\n", "def is_pred(w1, w2):\n    skip_count = 0\n    if len(w1)+1 != len(w2):\n        return False\n\n    for i in range(0, len(w1)):\n        if w1[i] == w2[i+skip_count]:\n            pass\n        elif skip_count == 0 and w1[i] == w2[i+1]:\n            skip_count += 1\n        else:\n            return False\n\n    return True\n\ndef tests():\n    assert is_pred('a', 'ab')\n    assert not is_pred('a', 'a')\n    assert not is_pred('a', 'bc')\n    assert not is_pred('ab', 'a')\n    \nclass Solution:\n\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        # tests()\n        words.sort(key=lambda w: len(w))\n        \n        chains = {}\n        current_max = 0\n        for w in words:\n            chains[w] = 1  \n            current_max = max(current_max, 1)\n            for chain, chain_len in list(chains.items()):\n                # if chain_len > chains[w] and is_pred(chain, w):\n                #     chains[w] = chain_len + 1\n                    \n                if is_pred(chain, w):\n                    chains[w] = max(chains[w], chain_len+1)\n                    current_max = max(current_max, chains[w])\n        \n        \n        return current_max\n    \n\n    # [a, ab, abc] abcd\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(w1, w2):\n            for i in range(len(w1)):\n                if(w1[i] != w2[i]):\n                    return w1[i:] == w2[i+1:]\n            \n            return True\n        \n        words.sort(key=len, reverse=True)\n        len_words = len(words)\n        combos = [0] * len_words\n        \n        for i in range(len_words):\n            for j in range(0, i):\n                if(len(words[i]) + 1 == len(words[j])\n                   and combos[i] < combos[j] + 1\n                   and is_predecessor(words[i], words[j])):\n                    # print(words[i] + ', ' + words[j])\n                    combos[i] = combos[j] + 1\n                    \n        # for i in range(len_words):\n        #     print(combos[i], end=', ')\n        #     print(words[i])\n        \n        \n        return max(combos) + 1\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        dp = [1 for i in range(len(words))]\n        for r in range(1, len(words)):\n            for l in range(r):\n                if len(words[r]) == len(words[l]) + 1:\n                    missingLetters = i = 0\n                    for j in range(len(words[r])):\n                        if i >= len(words[l]) or words[l][i] != words[r][j]:\n                            missingLetters += 1\n                            if missingLetters > 1:\n                                break\n                        else:\n                            i += 1\n                    if missingLetters == 1:\n                        dp[r] = max(dp[r], dp[l] + 1)\n        return max(dp)\n                \n                \n                \n            \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        words=sorted(words, key=len)\n        map={}\n        DP=[1 for idx in range(len(words))]\n       \n        \n        \n        for i in range(len(words)):\n            map={}\n            for j in range(0,i):\n                if len(words[i]) == len(words[j])+1:\n                    \n                    diff=0\n                    \n                    for comp in range(len(words[i])):\n                        if diff==0 and comp==len(words[i])-1:\n                            diff=1\n                            continue\n                        \n                        if words[i][comp]==words[j][comp-diff]:\n                            continue\n                        else:\n                            if diff==1:\n                                diff=69\n                                break\n                            else:\n                                diff=1\n                    \n                    if diff==1:\n                        if DP[j]+1>DP[i]:\n                            DP[i]=DP[j]+1\n\n        #print (words)\n        #print (DP) \n        return max(DP)\n                        \n                \n                \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        graph = collections.defaultdict(list)\n        maxlen = float('-inf')\n        minlen = float('inf')\n        for word in words:\n            graph[len(word)].append(word)\n            maxlen = max(maxlen, len(word))\n            minlen = min(minlen, len(word))\n        \n        # print(graph, minlen, maxlen)\n        \n        def predecessor(word1, word2):\n            \n            if len(word1)+1 != len(word2):\n                return False\n            if not word1:\n                return True\n            fill = 1\n            left, right = 0 ,0 \n            while left < len(word1) and right < len(word2):\n                if word1[left] != word2[right]:\n                    if fill:\n                        right += 1\n                        fill -= 1\n                        continue\n                    else:\n                        return False\n                left += 1\n                right += 1\n            # print(word1, word2, True)\n            return True\n            \n        def chain(length, s=''):\n            if length not in graph:\n                return 0\n            ans = 0\n            for w in graph[length]:\n                if predecessor(s, w):\n                    ans = max(ans, 1 + chain(length+1, w))\n            return ans\n        \n        ans = 1\n        for l in range(minlen, maxlen+1):\n            for w in graph[l]:\n                res = chain(l+1, w) +1 \n                # print(res)\n                ans = max(ans, res)\n        return ans\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(w1, w2):\n            # if(len(w1) + 1 != len(w2)):\n            #     return False\n            \n            skip = 0\n            for i in range(len(w2)):\n                j = i - skip\n                if(j == len(w1)):\n                    break\n                if(w1[j] != w2[i]):\n                    skip += 1\n                    if(skip >= 2):\n                        return False\n            \n            return True\n        \n        words.sort(key=len, reverse=True)\n        len_words = len(words)\n        combos = [0] * len_words\n        \n        for i in range(len_words):\n            for j in range(0, i):\n                \n                if(len(words[i]) + 1 == len(words[j])and combos[i] < combos[j] + 1 and is_predecessor(words[i], words[j])):\n                    # print(words[i] + ', ' + words[j])\n                    combos[i] = combos[j] + 1\n                    \n        for i in range(len_words):\n            print(combos[i], end=', ')\n            print(words[i])\n        \n        \n        return max(combos) + 1\n        ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        if not words:\n            return 0\n                \n        # O(n log n)\n        words = sorted(words, key = lambda x: len(x))\n                    \n        # O(n) space\n        dp = [1]*len(words)\n        \n        # O(n^2)\n        for i in range(1, len(words)):\n            \n            for j in range(i-1, -1, -1):\n                                \n                \n                if len(words[i]) == len(words[j])+1:\n                    \n                    update = True\n                    \n                    for c in words[j]:\n                        if c not in words[i]:\n                            update = False\n                    \n                    if update:\n                        dp[i] = max(dp[i], 1 + dp[j])\n                                                                            \n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        words=sorted(words, key=len)\n        \n        DP=[1 for idx in range(len(words))]\n       \n        \n        \n        for i in range(len(words)):\n            \n            for j in range(0,i):\n                if len(words[i]) == len(words[j])+1:\n                    \n                    diff=0\n                    \n                    for comp in range(len(words[i])):\n                        \n                        if diff==0 and comp==len(words[i])-1:\n                            diff=1\n                            \n                        elif words[i][comp]!=words[j][comp-diff]:\n                            if diff==1:\n                                diff=None\n                                break\n                            else:\n                                diff=1\n                    \n                    if diff==1:\n                        if DP[j]+1>DP[i]:\n                            DP[i]=DP[j]+1\n\n\n        return max(DP)\n                        \n                \n                \n        \n", "class Solution:\n    def checkPredecessor(self, word_1, word_2):\n        find_extra = False\n        for i in range(len(word_1)):\n            chr_1 = word_1[i]\n            if not find_extra:\n                chr_2 = word_2[i]\n            else:\n                chr_2 = word_2[i + 1]\n            if chr_1 != chr_2:\n                if find_extra:\n                    return False\n                else:\n                    if chr_1 != word_2[i + 1]:\n                        return False\n                    find_extra = True\n        return True\n            \n    \n    def longestStrChain_old(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        longest_seq = [1] * len(words)\n        for i in range(1, len(words)):\n            curr_word = words[i]\n            for j in range(0, i)[::-1]:\n                prev_word = words[j]   \n                if len(prev_word) == len(curr_word):\n                    continue\n                if len(prev_word) + 1 < len(curr_word):\n                    break\n                if self.checkPredecessor(prev_word, curr_word):\n                    longest_seq[i] = max(longest_seq[i], longest_seq[j] + 1)\n        return max(longest_seq)\n    \n    def longestStrChain(self, words):\n        words.sort(key=lambda x: len(x))\n        longest_chain = {}\n        \n        for word in words:\n            longest_chain[word] = max([longest_chain.get((word[:i] + word[i + 1:]), 0) for i in range(len(word))]) + 1\n        \n        return max(longest_chain.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        words=sorted(words, key=len)\n        map={}\n        DP=[1 for idx in range(len(words))]\n       \n        \n        \n        for i in range(len(words)):\n            map={}\n            for j in range(0,i):\n                if len(words[i]) == len(words[j])+1:\n                    \n                    diff=0\n                    \n                    for comp in range(len(words[i])):\n                        \n                        if diff==0 and comp==len(words[i])-1:\n                            diff=1\n                            \n                        elif words[i][comp]!=words[j][comp-diff]:\n                            if diff==1:\n                                diff=None\n                                break\n                            else:\n                                diff=1\n                    \n                    if diff==1:\n                        if DP[j]+1>DP[i]:\n                            DP[i]=DP[j]+1\n\n        #print (words)\n        #print (DP) \n        return max(DP)\n                        \n                \n                \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        n = len(words)\n        dp = [1] * n\n        for i in range(1, n):\n            word = words[i]\n            word_len = len(word)\n            for j in range(0, i):\n                if len(words[j]) == word_len - 1:\n                    flag = False\n                    for t in range(word_len):\n                        if word[:t] + word[t+1:] == words[j]:\n                            flag = True\n                    if flag:\n                        dp[i] = max(dp[i], dp[j] + 1)\n        return max(dp)\n                \n            \n            \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def check(s, t):\n            m, n = len(s), len(t)\n            flag = False\n            j = 0\n            if n != m + 1:\n                return False\n            for i in range(n):\n                \n                if j < m and t[i] == s[j]:\n                    j += 1\n                else:\n                    if not flag:\n                        flag = True\n                    else:\n                        return False\n            return True\n        words = sorted(words, key = lambda entry: len(entry), reverse = False)        \n        table = [1]*len(words)\n        for i in range(1, len(table)):\n            maxVal = 0\n            for j in range(i):\n                if (len(words[j]) + 1 == len(words[i])) and check(words[j], words[i]) and (table[i] < table[j] + 1):\n                    table[i] = table[j] + 1\n        return max(table)\n                    \n                            \n                        \n                    \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        words = sorted(words, key=lambda x: len(x))\n        print(words)\n        def valid(word1, word2):\n            i = 0\n            j = 0\n            flag = False\n            while i < len(word1) and j < len(word2):\n                if word1[i] == word2[j]:\n                    i += 1\n                    j += 1\n                    continue\n                if not flag and word1[i] != word2[j]:\n                    flag = True\n                    j += 1\n                    continue\n                if flag and word1[i] != word2[j]:\n                    return False\n            \n            return i == len(word1)\n                \n        \n        res = 1\n        dp = [1] * len(words)\n        for i in range(1, len(words)):\n            for j in range(i):\n                if len(words[j]) + 1 == len(words[i]) and valid(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j]+1)\n            res = max(res, dp[i])\n        # print(dp)\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def ispre(w1, w2):\n            i, j = 0, 0\n            while i < len(w1) and j < len(w2):\n                if w1[i] == w2[j]:\n                    i += 1\n                    j += 1\n                else:\n                    j += 1\n            return i == len(w1)\n        \n        words.sort(key=len)\n        dp = [0] * len(words)\n        \n        def dfs(i):\n            if dp[i] != 0:\n                return dp[i]\n            dp[i] = 1\n            for j in range(i, len(words)):\n                if len(words[j]) <= len(words[i]):\n                    continue\n                if len(words[j]) > len(words[i]) + 1:\n                    break\n                if ispre(words[i], words[j]):\n                    dp[i] = max(dp[i], 1 + dfs(j))\n            return dp[i]\n            \n        ans = max(dfs(i) for i in range(len(words)))\n        return ans", "class Solution:\n    def is_chainable(self, shorter, longer):\n        for i in range(len(longer)):\n            if shorter == longer[:i] + longer[i+1:]:\n                return True\n        return False\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        sw = sorted(words, key=lambda x: len(x))\n        n_words = len(sw)\n        chains = [1] * n_words\n        out = 1\n        for i in range(n_words):\n            word = sw[i]\n            for j in range(i+1, n_words):\n                next_word = sw[j]\n\n                if len(word)==len(next_word):\n                    continue\n                elif len(word)-len(next_word) != -1:\n                    break\n\n                if self.is_chainable(word, next_word):\n                    chains[j] = chains[i] + 1\n                    out = max(out, chains[j])\n        return out\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        ans = 1\n        dp = [1 for i in range(len(words))]\n        for r in range(1, len(words)):\n            for l in range(r):\n                if len(words[r]) == len(words[l]) + 1:\n                    missingLetters = 0\n                    i = 0\n                    for j in range(len(words[r])):\n                        if i >= len(words[l]) or words[l][i] != words[r][j]:\n                            missingLetters += 1\n                            if missingLetters > 1:\n                                break\n                        else:\n                            i += 1\n                    if missingLetters == 1:\n                        dp[r] = max(dp[r], dp[l] + 1)\n                        ans = max(ans, dp[r])\n        return ans\n                \n                \n                \n            \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        n = len(words)\n        dp = [1] * n\n        for i in range(1, n):\n            word = words[i]\n            word_len = len(word)\n            for j in range(0, i):\n                flag = False\n                if len(words[j]) == word_len - 1:\n                    for t in range(word_len):\n                        if word[:t] + word[t+1:] == words[j]:\n                            flag = True\n                if flag:\n                    dp[i] = max(dp[i], dp[j] + 1)\n        return max(dp)\n                \n            \n            \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        if len(words)==0:\n            return 0\n        def isRelate(small:str,big:str) -> bool:\n            for i in range(len(big)):\n                if small==big[:i]+big[i+1:]:\n                    return True\n            return False\n        def lengthList(target:int)-> List[str]:\n            if target==0:\n                return []\n            final=[]\n            for i in words:\n                if len(i)==target:\n                    final.append(i)\n            return final\n        \n        dp=collections.defaultdict(int)\n        words.sort(key=lambda x:len(x))\n        for word in words:\n            compareList=lengthList(len(word)-1)\n            maxx=0\n            if len(compareList)==0:\n                dp[word]=1\n            else:\n                \n                for small in compareList:\n                    if isRelate(small,word):\n                        maxx=max(maxx,dp[small])\n        \n                dp[word]=maxx+1\n        \n        \n        return max(dp.values())\n                \n        \n\n\n                    \n#         def recur(word:str,words:List[str],remain:List[str],length:int):\n#             if len(word)==len(max(words)) and len(remain)==0:\n#                 return 1\n            \n", "#sort words by length, and we will attempt to shrink longer words and jump backwards to calculated length\n#store dictionary of all words, with the chain length being 1\n#for each word, iteratively remove one letter (O(k), k = len(word))\n#check if the smaller word is now in the dictionary, and if it is, increase the current words chain length to be the smaller words chain + 1\n#keep track of longest chain\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        word_list = sorted(words, key = lambda x: len(x))\n        word_dict = {word:1 for word in word_list}\n        \n        longest = 0\n        for word in word_list:\n            for i in range(len(word)):\n                test = word[:i] + word[i+1:]\n                if test in word_dict:\n                    word_dict[word] = word_dict[test] + 1\n                longest = max(longest, word_dict[word])\n        return longest\n", "from collections import Counter\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def in_c(a: int, b: int):\n            for k, v in list(a.items()):\n                if k not in b or b[k] < v:\n                    return False\n            return True\n\n        N = len(words)\n        words = sorted(words, key=lambda i:len(i))\n        word_c = [Counter(ii) for ii in words]\n        dp = [1] * N\n        for ii in range(N):\n            can = [kk for jj, kk, mm in zip(word_c[:ii], dp[:ii], words[:ii]) if len(words[ii]) == len(mm) + 1 and in_c(jj, word_c[ii])]\n            if can:\n                dp[ii] = max(can) + 1\n        print(words)\n        print(dp)\n        return max(dp)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        words.sort(key = lambda w: len(w))\n        \n        def predecessor(a: str, b: str):\n            if len(b) - len(a) == 1:\n                mismatch = 0\n                a_idx , b_idx = 0, 0\n                \n                while a_idx < len(a) and mismatch <=1:\n                    \n                    if a[a_idx] != b[b_idx]:\n                        mismatch +=1\n                        b_idx +=1\n                    else:\n                        a_idx = a_idx+1\n                        b_idx = b_idx+1\n                         \n                if mismatch == 1 or not mismatch: return True\n            \n            return False\n        \n        ## max length end at word i\n        dp = [1]\n        for word in words[1:]:\n            max_length = 1\n            for i in range(len(dp)):\n                if predecessor(words[i], word):\n                    max_length = max(max_length, dp[i] + 1)\n                    \n            dp.append(max_length)\n            \n        \n        return max(dp)\n                \n            \n            \n                \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = [ 1 for i in range(len(words))]\n        words.sort(key=lambda x:len(x))\n        for i in range(len(words)):\n            for j in range(i):\n                if len(words[j]) == len(words[i]):\n                    continue\n                if len(words[i]) - len(words[j]) > 1:\n                    continue\n                else:\n                    count = 0\n                    for ch in words[j]:\n                        if ch in words[i]:\n                            count += 1\n                    \n                    if count == len(words[j]):\n                        dp[i] = dp[j] + 1\n        \n        return max(dp)\n    \n                            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def connected(x, y):\n            i, j = 0, 0\n            count = 0\n            while i < len(y) and j < len(x):\n                if y[i] != x[j]:\n                    if count == 0:\n                        j += 1\n                        count += 1\n                    else:\n                        return False\n                else:\n                    i += 1\n                    j += 1\n            return True\n                    \n        sort_words = sorted(words, key=len) \n        res = [1 for i in range(len(sort_words))]\n        \n        for i in range(len(sort_words)):\n            x = sort_words[i]\n            for j in range(i, len(sort_words)):\n                y = sort_words[j]\n                if len(y) == len(x)+1 and connected(y, x):\n                    res[j] = max(res[j], res[i]+1)\n                elif len(y) > len(x)+1:\n                    break\n        return max(res)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPred(w1,w2):\n            if len(w1)!=(len(w2)-1):\n                return False\n            i,j = 0,0\n            while i<len(w1):\n                if w1[i]!=w2[j]:\n                    if i!=j:\n                        return False\n                    j+=1\n                else:\n                    i+=1\n                    j+=1\n            return True\n            \n        \n\n        words=sorted(words,key=lambda x: len(x))\n        dp = [1]*len(words)\n        for i in range(len(words)):\n            for j in range(i): \n                if isPred(words[j],words[i]):\n                    dp[i] = max(dp[i],dp[j]+1)\n        return max(dp)\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if(len(words)==0):\n            return False\n        words.sort(key=lambda x:len(x))\n        def check(a, b):\n            for i in range(len(b)-1):\n                if(a[i]!=b[i]):\n                    return(b[i+1:]==a[i:])\n            return True\n        ans = 1\n        dp = [1]*len(words)\n        for i in range(len(words)):\n            for j in range(i+1, len(words)):\n                if(len(words[j])>1+len(words[i])):\n                    break\n                if(len(words[j])==1+(len(words[i]))):\n                    if(check(words[i], words[j])):\n                        dp[j] = max(dp[j], 1+dp[i])\n                        ans = max(ans, dp[j])\n        return ans", "# class Solution:\n#     def longestStrChain(self, words: List[str]) -> int:\n        \n        \n#         https://leetcode.com/problems/longest-string-chain/discuss/585044/C%2B%2B-Using-unordered_map-and-DP\n# DP\n\n# 1. sort words in increasing order of length\n# 2. if len is same\n\n# LIS\n\n# dp[i] = longest word chain including index i\n# return max(dp)\n\n# dp[i] = max(dp[i], 1+ dp[j])\n# len(words[j]) + 1 = len(words[i])\n# ba, bda-> check all chars of j are in j in the same order\n\n# O(n^2*16)\n\n\n\n\n\nfrom collections import deque\n\ndef getKey(item):\n    return len(item)\n\ndef isPred(word1, word2):\n    word1 = list(word1)\n    word2 = list(word2)\n    q1 = deque(word1)\n    q2 = deque(word2)\n    while q1 and q2:\n        if q1[0] == q2[0]:\n            q1.popleft()\n            q2.popleft()\n        else:\n            q2.popleft()\n    if (not q1) and len(q2) <= 1:\n        return True\n    return False\n    \n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=getKey)\n        dp = [1]*len(words)\n        \n        for i in range(1, len(dp)):\n            for j in reversed(list(range(0, i))):\n                if len(words[j]) == len(words[i]):\n                    continue\n                elif len(words[j]) + 1== len(words[i]):\n                    if isPred(words[j], words[i]):\n                        dp[i] = max(dp[i], 1+ dp[j])\n                else:\n                    break\n        \n        return max(dp)\n        \n        \n\n\n# We can also think of thi problem as LIS problem \n\n\n# 1. Sort the words according to their length\n# Input: [\\\"a\\\",\\\"b\\\",\\\"ba\\\",\\\"bca\\\",\\\"bda\\\",\\\"bdca\\\"]\n# When you reach bdca ..check if dca is present..check if bca is present..check if bda is present..check if bdc is present\n# 2. So store each word in a hashmap form lookup in O(1)\n\n# 3. For each word in order of length, for each word2 which is word with one character removed, dp[word] = max(dp[word], dp[word2] + 1).\n# The maxm element in the dp array is the answer.\n\n\n\n# Clean implementation\n\n# https://leetcode.com/problems/longest-string-chain/discuss/376724/C%2B%2B-Simple-clean\n\n\n\n\n\n# Explaiantion:\n\n# https://leetcode.com/problems/longest-string-chain/discuss/295182/C%2B%2B-Bottom-Up-DP-solution-(with-Explanation)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        words.sort(key=len)\n        f = [1] * n\n        \n        def ispre(w1, w2):\n            if len(w1) != len(w2) - 1:\n                return False\n            i = j = 0\n            diff = False\n            while i < len(w1) and j < len(w2):\n                if w1[i] != w2[j]:\n                    if not diff:\n                        diff = True\n                        j += 1\n                        continue\n                    else:\n                        return False\n                i += 1\n                j += 1\n            return True\n        \n        res = 1\n        for i in range(1, n):\n            for j in range(i):\n                if ispre(words[j], words[i]):\n                    #print(words[j], words[i])\n                    f[i] = max(f[i], f[j] + 1)\n            res = max(res, f[i])\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) == 0:\n            return 0\n        \n        def findDistance(shorterString, longerString):\n            if len(longerString) - len(shorterString) != 1:\n                return False\n            i, j = 0, 0\n            edits = 0\n            while j < len(shorterString):\n                if longerString[i] != shorterString[j]:\n                    if edits == 0:\n                        i+=1\n                        edits += 1\n                        continue\n                    else:\n                        return False\n                i += 1\n                j += 1\n            return True\n        \n        dp = [1]*len(words)\n        words = sorted(words, key=lambda x: len(x))\n        maxAnswer = 0\n        for i in range(len(words)):\n            temp = 1\n            for j in range(i+1):\n                if findDistance(words[j], words[i]):\n                    temp = max(temp, dp[j]+1)\n            dp[i] = temp\n            maxAnswer = max(maxAnswer, dp[i])\n        # print(dp)\n        return maxAnswer", "def find(s1,s2):\n    i = 0\n    j = 0\n    count = 0\n    while i < len(s1) and j < len(s2):\n        if s1[i] == s2[j]:\n            i += 1\n            j += 1\n        else:\n            j += 1\n            count += 1\n    \n    if i == len(s1):\n        return True\n    if count == 1:\n        return True\n    \n    return False\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        new_words = []\n        for w in words:\n            new_words.append((len(w),w))\n        \n        new_words.sort()\n        dp = [1]*len(words)\n        for i in range(len(words)):\n            for j in range(i+1,len(words)):\n                l1,w1 = new_words[i]\n                l2,w2 = new_words[j]\n                if l2-l1 > 1:\n                    break\n                if l2-l1 == 1:\n                    diff = find(w1,w2)\n                    if diff == 1:\n                        dp[j] = max(dp[j],dp[i]+1)\n        \n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        dp = collections.defaultdict(int)\n        for word in words:\n            dp[word] = max([dp[word[:i] + word[i + 1:]] for i in range(len(word))]) + 1\n        return max(dp.values()) ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def if_pred(a, b):\n            if len(a) + 1 != len(b): \n                return False \n            i = 0 \n            j = 0 \n            while i < len(a): \n                if a[i] == b[j]: \n                    i += 1 \n                j += 1 \n                \n                if j - i > 1: \n                    return False                 \n            else: \n                return True \n                \n        words.sort(key=lambda x: len(x))        \n        dp = [1 for _ in range(len(words))]\n        \n        for i in range(len(words)): \n            for j in range(i-1, -1, -1):\n                if if_pred(words[j], words[i]): \n                    dp[i] = max(dp[i], dp[j] + 1)\n\n                        \n        print(dp)\n        return max(dp)\n\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words_sort = [(len(word), word) for word in words]\n        words_sort.sort()\n        words = [word for w_len, word in words_sort]\n        \n        \n        def isPredecessor(pre:str, succ:str) -> bool:\n            \n            if len(pre) != len(succ)-1:\n                return False\n            \n            pre = pre + '.'\n            d = 0\n            for i in range(len(succ)):\n                if pre[i-d] != succ[i]:\n                    d += 1\n                    if d>=2:\n                        return False\n            return True\n        \n        \n        chain = [1] * len(words)\n        ans = 1\n        for i in range(len(words)):\n            for j in range(0, i):\n                if isPredecessor(words[j], words[i]):\n                    chain[i] = max(chain[i], chain[j]+1)\n                    ans = max(ans, chain[i])\n        \n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def if_pred(a, b):\n            if len(a) + 1 != len(b): \n                return False \n            i = 0 \n            j = 0 \n            while i < len(a): \n                if a[i] == b[j]: \n                    i += 1 \n                j += 1 \n                \n                if j - i > 1: \n                    return False                 \n            else: \n                return True \n                \n        words.sort(key=lambda x: len(x))        \n        dp = [1 for _ in range(len(words))]\n        \n        for i in range(len(words)): \n            for j in range(i-1, -1, -1):\n                if if_pred(words[j], words[i]): \n                    if dp[i] < dp[j] + 1: \n                        dp[i] =  dp[j] + 1\n\n                        \n        print(dp)\n        return max(dp)\n\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def determine(s1, s2):\n            if len(s2) != len(s1) + 1:\n                return False\n            \n            insert = False\n            j = 0\n            for i in range(len(s1)):\n                while s2[j] != s1[i]:\n                    # print(s2[j], s1[i])\n                    if insert: return False\n                    j = j + 1\n                    insert = True\n                j = j + 1\n            return True\n        \n        d = {}\n        words = sorted(words, key = lambda x: len(x))\n        d[words[-1]] = 1\n        for i in reversed(list(range(len(words)-1))):\n            m = 0\n            d[words[i]] = 1\n            for j in range(i, len(words)):\n                # print(words[i], words[j], determine(words[i], words[j]))\n                if determine(words[i], words[j]):\n                    if d[words[j]] > m:\n                        d[words[i]] = d[words[j]] + 1\n                        m = d[words[i]]\n                        \n        # print(d)\n                        \n        out = 0\n        for k in d:\n            if d[k] > out:\n                out = d[k]\n        \n        return out\n                    \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPred(w1,w2):\n            if len(w1)!=(len(w2)-1):\n                return False\n            i,j = 0,0\n            while i<len(w1):\n                if w1[i]!=w2[j]:\n                    if i!=j:\n                        return False\n                    j+=1\n                else:\n                    i+=1\n                    j+=1\n            return True\n           \n        words=sorted(words,key=lambda x: len(x))\n        dp = [1]*len(words)\n        for i in range(len(words)):\n            for j in range(i): \n                if isPred(words[j],words[i]):\n                    dp[i] = max(dp[i],dp[j]+1)\n        return max(dp)\n            \n", "def is_pred(w1, w2):\n    skip_count = 0\n    if len(w1)+1 != len(w2):\n        return False\n\n    for i in range(0, len(w1)):\n        if w1[i] == w2[i+skip_count]:\n            pass\n        elif skip_count == 0 and w1[i] == w2[i+1]:\n            skip_count += 1\n        else:\n            return False\n\n    return True\n\ndef tests():\n    assert is_pred('a', 'ab')\n    assert not is_pred('a', 'a')\n    assert not is_pred('a', 'bc')\n    assert not is_pred('ab', 'a')\n    \nclass Solution:\n\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        # tests()\n        words.sort(key=lambda w: len(w))\n        \n        chains = {}\n        current_max = 0\n        for w in words:\n            chains[w] = 1  \n            current_max = max(current_max, 1)\n            word_max = 1\n            for chain, chain_len in list(chains.items()):\n                # if chain_len > chains[w] and is_pred(chain, w):\n                #     chains[w] = chain_len + 1\n                    \n                if is_pred(chain, w) and word_max < chain_len+1:\n                    # chains[w] = max(chains[w], chain_len+1)\n                    chains[w] = chain_len+1\n                    word_max = chain_len+1\n                    current_max = max(current_max, word_max)\n        \n        \n        return current_max\n    \n\n    # [a, ab, abc] abcd\n", "from collections import Counter\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = [1] * len(words)\n        words.sort(key=len)\n        for i in range(1, len(words)):\n            d1 = Counter(words[i])\n            for j in range(i):\n                if len(words[i]) - len(words[j]) == 1:\n                    d2 = Counter(words[j])\n                    check = 0\n                    for k in d1:\n                        if k not in d2:\n                            check += 1\n                        elif d2[k] != d1[k]:\n                            check += 1\n                        if check == 2:\n                            break\n                    if check == 1:\n                        dp[i] = max(dp[i], dp[j]+1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_pred(short, long):\n            if len(short) + 1 != len(long):\n                return False\n            short +=  ' '\n            new = None\n            for i in range(len(long)):\n                if short[i] != long[i]:\n                    new = i\n                    break\n            if short[:-1] == long[:new] + long[(new+1):]:\n                return True\n            return False\n        words.sort(key = lambda x : len(x)) \n        dp = [1]*len(words)\n        for i in range(1, len(words)):\n            for j in range(i):\n                if is_pred(words[j], words[i]):\n                    if dp[j] >= dp[i]:\n                        dp[i] = dp[j] + 1\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        self.res = 0\n        \n        def compare(w1, w2):\n            if len(w1) > len(w2):\n                w1, w2 = w2, w1\n                \n            if len(w2) - len(w1) != 1:\n                return False\n            \n            i, j = 0, 0\n            \n            flag = False\n            while i < len(w1) or j < len(w2):\n                if i < len(w1) and w1[i] == w2[j]:\n                    i += 1\n                    j += 1\n                \n                elif not flag:\n                    flag = True\n                    j += 1\n                    \n                else:\n                    return False\n                \n            return True\n        \n        @lru_cache(maxsize=None)\n        def dfs(w):\n            length = 0\n            for word in words:\n                if len(word) - len(w) == 1 and compare(w, word):\n                    length = max(dfs(word), length)\n                    \n            ret = length + 1\n            self.res = max(ret, self.res)\n            return ret\n        \n        for w in words:\n            dfs(w)\n            \n        return self.res\n        \n                \n            \n        \n", "def is_pred(w1, w2):\n    skip_count = 0\n    if len(w1)+1 != len(w2):\n        return False\n\n    for i in range(0, len(w1)):\n        if w1[i] == w2[i+skip_count]:\n            pass\n        elif skip_count == 0 and w1[i] == w2[i+1]:\n            skip_count += 1\n        else:\n            return False\n\n    return True\n\ndef tests():\n    assert is_pred('a', 'ab')\n    assert not is_pred('a', 'a')\n    assert not is_pred('a', 'bc')\n    assert not is_pred('ab', 'a')\n    \nclass Solution:\n\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        tests()\n        words.sort(key=lambda w: len(w))\n        \n        chains = {}\n        current_max = 0\n        for w in words:\n            chains[w] = 1  \n            current_max = max(current_max, 1)\n            for chain, chain_len in list(chains.items()):\n                if is_pred(chain, w):\n                    if w in chains:\n                        chains[w] = max(chains[w], chain_len+1)\n                    else: \n                        chains[w] = chain_len + 1\n                    current_max = max(current_max, chains[w])\n        \n        \n        return current_max\n    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        words.sort(key = lambda x: len(x))\n        for w in words:\n            maxLen = 0\n            for i in range(len(w)):\n                predecessor = w[:i] + w[i+1:]\n                maxLen = max(maxLen, dp.get(predecessor, 0) + 1)\n            dp[w] = maxLen\n        return max(dp.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def check(w1, w2):\n            if len(w1)!=len(w2)-1:\n                return False\n            cnt = 0\n            idx1 = 0\n            idx2 = 0\n            while idx1<len(w1) and idx2<len(w2) and cnt<=1:\n                if w1[idx1]==w2[idx2]:\n                    idx1 += 1\n                    idx2 += 1\n                else:\n                    cnt += 1\n                    idx2 += 1\n            if cnt==0 and idx1==len(w1) and idx2==len(w2)-1:\n                return True\n            elif cnt==1 and idx1==len(w1) and idx2==len(w2):\n                return True\n            else:\n                return False\n        \n        # print (check(words[0], words[1]))\n        # return\n        words.sort(key=len)\n        dp = [1 for _ in range(len(words))]\n        for j in range(len(words)):\n            for i in range(j):\n                if check(words[i], words[j]):\n                    # print (i, j)\n                    dp[j] = max(dp[j], dp[i]+1)\n        res = max(dp)\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def isPre(st1,st2):\n            if len(st2)!=len(st1)+1:\n                return False\n            j=0\n            diff=0\n            for i in range(len(st2)):\n                if diff>1:\n                    return False\n                elif j<len(st1) and st1[j]==st2[i]:\n                    j+=1\n                else:\n                    diff+=1\n            return diff<=1\n\n        words.sort(key=lambda x: len(x))\n        n=len(words)\n        dp=[1]*n\n        #print(words)\n        for i in range(1,n):\n            for j in range(i):\n                if isPre(words[j],words[i]):\n                    dp[i]=max(dp[i],dp[j]+1)\n        #print([(words[i],dp[i]) for i in range(n)])\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        '''\n        \n        abc dabc\n        \n        max_val = max(i->(0,len(a)) f(n,i-1))\n        \n        '''\n        def is_predessor(word1, word2):\n            \n            if(abs(len(word1) - len(word2)) > 1):\n                return False\n            else:\n                count = 0\n                word1_cnt = 0\n                word2_cnt = 0\n                \n                while(word1 and word2):\n                    if(word1[0] == word2[0]):\n                        word1 = word1[1:]\n                        word2 = word2[1:]\n                    else:\n                        count+=1\n                        word1 = word1[1:]\n                    \n                    if(count > 1):\n                        return False\n                \n                \n                return True\n        \n            \n        words = sorted(words, key = lambda x:len(x))\n        \n        M = [0]*len(words)\n        M[0] = 1\n        overall_max = float('-inf')\n        for i in range(1, len(M)):\n            max_val = float('-inf')\n            for j in range(i):\n                if((len(words[i]) != len(words[j])) and is_predessor(words[i], words[j])):\n                    max_val = max(max_val, 1 + M[j])\n                \n            M[i] = max(1, max_val)\n            overall_max = max(overall_max, M[i])\n        \n        return overall_max\n                \n            \n", "class Solution:\n    def predecessor(self, larger, smaller):\n        largerCount = Counter(larger)\n        for c in smaller:\n            if c in largerCount:\n                largerCount[c] -= 1\n                if largerCount[c] == 0:\n                    del largerCount[c]\n        mc = largerCount.most_common()\n        return len(mc) == 1 and mc[0][1] == 1\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        lengthToWords = defaultdict(list)\n        for word in words:\n            lengthToWords[len(word)].append(word)\n        wordToCL = defaultdict(lambda: 1)\n        res = 1\n        \n        for wordLength in range(16, 1, -1):\n            if wordLength - 1 not in lengthToWords:\n                continue\n            for larger in lengthToWords[wordLength]:\n                for smaller in lengthToWords[wordLength-1]:\n                    if self.predecessor(larger, smaller):\n                        wordToCL[smaller] = max(wordToCL[smaller], wordToCL[larger] + 1)\n                        res = max(res, wordToCL[smaller])\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def is_predecessor(word_short, word_long) -> bool:\n            if len(word_short)+1 != len(word_long):\n                return False\n            i_s = 0\n            can_skip = True\n            for i_l in range(len(word_long)):\n                if i_s > len(word_short)-1:\n                    return True\n                c_s = word_short[i_s]\n                c_l = word_long[i_l]\n                if c_s == c_l:\n                    i_s += 1\n                else:\n                    if can_skip:\n                        # i_s += 1\n                        can_skip = False\n                        pass\n                    else:\n                        return False\n            return True\n        \n        if not words:\n            return 0\n        \n        words.sort(key=lambda x: len(x))\n        # print(words)\n        dp = [1] * len(words)\n\n        for r in range(1, len(words)):\n            # print(r)\n            for l in range(r):\n                if is_predecessor(words[l], words[r]):\n                    # print('ok',words[l], words[r], l, dp[l])\n                    dp[r] = max(dp[r], dp[l]+1)\n                \n        # print(dp)\n        return max(dp)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPredecessor(w1, l1, w2, l2):\n            if l2 == l1 + 1:\n                for i in w1:\n                    if i not in w2:\n                        return False\n                return True\n            return False\n        \n        words.sort(key = lambda x: len(x))\n        L = [len(i) for i in words]\n        DP = [1 for i in range(len(L))]\n        \n        ans = 1\n        for i in range(1, len(L)):\n            for j in range(0,i):\n                if isPredecessor(words[j], L[j], words[i], L[i]):\n                    DP[i] = max(DP[j]+1, DP[i])\n            ans = max(ans, DP[i])\n        \n        return ans", "def isPredecessor(src, dst):\n    nsrc = len(src)\n    ndst = len(dst)\n    if nsrc+1 != ndst:\n        return False\n    \n    i = 0\n    while i < nsrc:\n        if src[i] == dst[i]:\n            i += 1\n            continue\n        else:\n            return src[i:] == dst[i+1:]\n    \n    return True\n        \nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        \n        mem_len = [-1 for _ in range(len(words))]\n        \n        def search(i):\n            if mem_len[i] != -1:\n                return \n            \n            ans = 1\n            for j in range(i+1, len(words)):    \n                if isPredecessor(words[i], words[j]):\n                    search(j)\n                    ans = max(ans, mem_len[j]+1)\n                    \n            mem_len[i] = ans\n            \n        for i in range(len(words)):\n            search(i)\n\n        return max(mem_len)", "from collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def isPartOfChain(longer,shorter):\n            if len(longer) - len(shorter) != 1:\n                return False \n            \n            short_ptr = 0\n            long_ptr = 0\n            \n            num_differences = 0\n            while long_ptr <= len(longer):\n                \n                \n                if num_differences > 1:\n                    return False\n\n                if short_ptr > len(shorter)-1:\n                    break\n                \n                if shorter[short_ptr] == longer[long_ptr]:\n                    short_ptr += 1\n                    long_ptr += 1\n                \n                else:\n                    long_ptr += 1\n                    num_differences += 1\n            \n            return True \n            \n    \n        def longestHelp(words):\n            \n            \n            if len(words) <= 1:\n                return 1\n            \n            \n            dp = [1 for _ in range(len(words))]\n            \n            #dp[i] = longest chain at words[i] \n            \n            # max_length is always 1 for each word\n            max_length = 1\n            for word in range(0,len(dp)):\n                for j in range(word-1,-1,-1):\n                    if isPartOfChain(words[word], words[j]):\n                        dp[word] = max(dp[word],1+dp[j])\n                        max_length = max(max_length, dp[word])\n\n\n            return max_length\n        \n        words.sort(key = len)\n        return longestHelp(words)\n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        lis = [1 for _ in range(n)]\n        def cmp(w1, w2):\n            for k in range(len(w1)):\n                if (w1[0:k] + w1[k+1:]) == w2:\n                    return True\n            return False\n        \n        words = sorted(words, key=len)\n        # print(words)\n        for i in range(1, n):\n            for j in range(i):\n                l1, l2 = len(words[j]), len(words[i])\n                if l1 == (l2 - 1):\n                    if cmp(words[i], words[j]):\n                        if lis[i] < lis[j] + 1:\n                            lis[i] = lis[j] + 1\n        \n        \n        # print(lis)\n        return max(lis)", "class Solution:\n    def _is_pred(self, word1: str, word2: str) -> bool:\n        if(not (len(word1) == len(word2)-1)):\n            return False\n        \n        for c in word1:\n            if c not in word2:\n                return False\n        \n        return True\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        n = len(words)\n        dp = [1 for i in range(n)]\n        \n        for i in range(n):\n            for j in range(i):\n                if(self._is_pred(words[j], words[i])):\n                    dp[i] = max(dp[i], dp[j] + 1)\n        \n        return (max(dp))", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = sorted(words, key=lambda w: len(w))\n        \n        seenCache = {}\n        max_len = 0\n        \n        for cur_word in words:\n            # print(cur_word)\n            cur_len = 0\n            for i in range(len(cur_word)):\n                check_word = cur_word[:i] + cur_word[i+1:]\n                cur_len = max(cur_len, seenCache.get(check_word, 0) + 1)\n                    \n            seenCache[cur_word] = cur_len\n            max_len = max(max_len, cur_len)\n        \n        return max_len", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        if not words:\n            return 0\n        n = len(words)\n        dp = [1] * n\n        for i in range(n):\n            for j in range(i):\n                if self.valid(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n\n        return max(dp)\n\n    def valid(self, str1, str2):\n        if len(str1)+1 != len(str2):\n            return False\n        cnt = 0\n        n = len(str1)\n        l1, l2 = 0, 0\n        while l1 < n and l2 < n + 1:\n            if cnt > 1:\n                return False\n\n            if str1[l1] != str2[l2]:\n                l2 += 1\n                cnt += 1\n            else:\n                l1 += 1\n                l2 += 1\n\n        return cnt <= 1 \n\n\n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        words.sort(key = lambda x: len(x))\n\n        #start with any word in words, find the chain.\n        #if a word is chained in other word chain, it cannot be a beginning word\n        visited = set()\n        res = 1\n        for i in range(len(words)):\n            if words[i] in visited:\n                continue\n            visited.add(words[i])\n            res = max(res, self.dfs(words, words[i], i + 1, visited))\n        \n        return res\n    \n    def dfs(self, words, cur, start, visited):\n        if start >= len(words):\n            return 1\n        ma = 1\n        for i in range(start, len(words)):\n            if len(words[i]) > len(cur) + 1:\n                break\n            if len(words[i]) == len(cur):\n                continue\n            if not self.isPredecessor(cur, words[i]):\n                continue\n            visited.add(words[i])\n            ma = max(ma, 1 + self.dfs(words, words[i], i + 1, visited))\n        \n        return ma\n    \n    def isPredecessor(self, w1, w2):\n        #print(w1, w2)\n        for i in range(len(w1)):\n            if w1[:i] == w2[:i] and w1[i:] == w2[i + 1:]:\n                #print(\\\"True\\\")\n                return True\n        #\u4e0d\u8981\u5fd8\u8bb0\u68c0\u67e5\u4e00\u4e0b\u8fd9\u79cd\u60c5\u51b5\uff0c\u6ca1\u88ab\u5305\u542b\u5728\u4e0a\u9762\n        if w1 == w2[:-1]:\n            return True\n        return False", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPred(w1,w2):\n            i,j = 0, 0\n            if len(w1)!=(len(w2)-1):\n                return False\n            while i < len(w1):\n                if w1[i] != w2[j]:\n                    if j != i:\n                        return False\n                    j += 1\n                else:\n                    j += 1\n                    i += 1\n            return True\n\n        \n        words=sorted(words,key=lambda x: len(x))\n        dp = [1]*len(words)\n        for i in range(len(words)):\n            for j in range(i): \n                if isPred(words[j],words[i]):\n                    dp[i] = max(dp[i],dp[j]+1)\n        return max(dp)\n            \n", "class Solution:\n    \n    def can_move(self, a, b):\n        b_letters = Counter(b)\n        \n        for char in a:\n            b_letters[char] -= 1\n        \n            if b_letters[char] < 0:\n                return False\n            elif b_letters[char] == 0:\n                b_letters.pop(char)\n        \n        return b_letters.popitem()[1] == 1\n\n\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda w: len(w))\n        \n        depths = {}\n        def recur(index):\n            if index not in depths:\n                s = words[index]\n\n                mx = 0\n                for i in range(index + 1, len(words)):\n                    if len(words[i]) - len(s) == 1 and self.can_move(s, words[i]):\n                        mx = max(recur(i), mx)\n                        \n                depths[index] = mx + 1\n                        \n            return depths[index]\n        \n        for i in range(len(words)):\n            recur(i)\n        \n        return max(depths.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # O(NNS) Solution\n        predecessors = dict()\n        words = sorted(words, key=len)\n        for i in range(len(words)):\n            predecessors[words[i]] = []\n            for j in range(i):\n                if self.isPredecessor(words[i], words[j]):\n                    predecessors[words[i]].append((words[j],j))\n        #print(words)\n        #print(predecessors)\n        T = [0] * len(words)\n        T[0] = 1\n        for i in range(1, len(words)):\n            if predecessors[words[i]]:\n                T[i] = max([T[j[1]] for j in predecessors[words[i]]]) + 1\n            else:\n                T[i] = 1\n        return max(T)\n            \n    def isPredecessor(self, word, candidate):\n        if len(candidate) + 1 != len(word):\n            return False\n        i, j = 0, 0\n        wildcard = True\n        while i < len(word) and j < len(candidate):\n            if word[i] == candidate[j]:\n                i += 1\n                j += 1\n            else:\n                if wildcard:\n                    i += 1\n                    wildcard = False\n                else:\n                    return False\n        return i+1 == len(word) or i == len(word) if wildcard else i == len(word)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        words.sort(key=lambda x : len(x))\n        f = [1] * n\n        \n        def ispre(w1, w2):\n            if len(w1) != len(w2) - 1:\n                return False\n            l1, l2 = sorted(w1), sorted(w2)\n            i = j = 0\n            diff = False\n            while i < len(l1) and j < len(l2):\n                if l1[i] != l2[j]:\n                    if not diff:\n                        diff = True\n                        j += 1\n                        continue\n                    else:\n                        return False\n                i += 1\n                j += 1\n            return True\n        \n        res = 1\n        for i in range(1, n):\n            for j in range(i):\n                if ispre(words[j], words[i]):\n                    #print(words[j], words[i])\n                    f[i] = max(f[i], f[j] + 1)\n            res = max(res, f[i])\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # O(NNS) Solution\n        predecessors = dict()\n        words = sorted(words, key=len)\n        for i in range(len(words)):\n            predecessors[words[i]] = []\n            for j in range(i):\n                if self.isPredecessor(words[i], words[j]):\n                    predecessors[words[i]].append((words[j],j))\n        print(words)\n        print(predecessors)\n        T = [0] * len(words)\n        T[0] = 1\n        for i in range(1, len(words)):\n            if predecessors[words[i]]:\n                T[i] = max([T[j[1]] for j in predecessors[words[i]]]) + 1\n            else:\n                T[i] = 1\n        return max(T)\n            \n    def isPredecessor(self, word, candidate):\n        if len(candidate) + 1 != len(word):\n            return False\n        i, j = 0, 0\n        wildcard = True\n        while i < len(word) and j < len(candidate):\n            if word[i] == candidate[j]:\n                i += 1\n                j += 1\n            else:\n                if wildcard:\n                    i += 1\n                    wildcard = False\n                else:\n                    return False\n        return i+1 == len(word) or i == len(word) if wildcard else i == len(word)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda word: (len(word)))\n        lengths = [1] * len(words)\n        for i in range(len(words)):\n            for j in range(i):\n                if self.checkifSuccessor(words[j],words[i]):\n                    lengths[i] = max(lengths[i], lengths[j] + 1)\n        return max(lengths)\n                    \n                \n    def checkifSuccessor(self, word1, word2):\n        if len(word1) + 1 !=  len(word2):\n            return False\n        else:\n            indexOfword1 = 0\n            differentReached = False\n            for a in range(len(word2)):\n                if indexOfword1 == len(word1):\n                    return True\n                if word2[a] == word1[indexOfword1]:\n                    indexOfword1 += 1\n                else:\n                    if differentReached == True:\n                        return False\n                    else:\n                        differentReached = True\n            return True\n            \n                    \n", "from collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = defaultdict(int)\n        words.sort(key = lambda x: len(x))\n        for w in words:\n            maxLen = 0\n            for i in range(len(w)):\n                predecessor = w[:i] + w[i+1:]\n                maxLen = max(maxLen, dp[predecessor] + 1)\n            dp[w] = maxLen\n        return max(dp.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        N = len(words)\n        \n        def is_predecessor(word1: str, word2: str) -> bool:\n            if (len(word1) + 1 == len(word2)):\n                diffCount = 0\n                i, j = 0, 0\n                while (i < len(word1) and j < len(word2)):\n                    if (word1[i] == word2[j]):\n                        i += 1\n                        j += 1\n                    elif (diffCount == 0):\n                        j += 1\n                        diffCount = 1\n                    else:\n                        return False\n                return True\n            return False\n        \n        def backtracking(start: int, count: int) -> int:\n            if (start in memo):\n                return memo[start]\n            \n            sublongest = count\n            for i in range(start + 1, N):\n                if (is_predecessor(words[start], words[i])):\n                    sublongest = max(sublongest, backtracking(i, count + 1))\n            memo[start] = sublongest\n            return sublongest\n        \n        words.sort(key = lambda x: (len(x), x))\n        \n        memo = dict()\n        longest = 0\n        for i in range(N):\n            longest = max(longest, backtracking(i, 1))\n        return longest", "class Solution:\n    def checkPredecessor(self, word_1, word_2):\n        find_extra = False\n        if len(word_1) + 1 != len(word_2):\n            return False\n        for i in range(len(word_1)):\n            chr_1 = word_1[i]\n            if not find_extra:\n                chr_2 = word_2[i]\n            else:\n                chr_2 = word_2[i + 1]\n            if chr_1 != chr_2:\n                if find_extra:\n                    return False\n                else:\n                    if chr_1 != word_2[i + 1]:\n                        return False\n                    find_extra = True\n        return True\n            \n    \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        longest_seq = [1] * len(words)\n        for i in range(1, len(words)):\n            curr_word = words[i]\n            for j in range(0, i):\n                prev_word = words[j]\n                if self.checkPredecessor(prev_word, curr_word):\n                    longest_seq[i] = max(longest_seq[i], longest_seq[j] + 1)\n        return max(longest_seq)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda word: (len(word)))\n        lengths = [1] * len(words)\n        for i in range(len(words)):\n            for j in range(i):\n                if self.checkifSuccessor(words[j],words[i]):\n                    lengths[i] = max(lengths[i], lengths[j] + 1)\n        return max(lengths)\n                    \n                \n    def checkifSuccessor(self, word1, word2):\n        if len(word1) + 1 !=  len(word2):\n            return False\n        else:\n            indexOfword1 = 0\n            differentReached = False\n            for a in range(len(word2)):\n                if indexOfword1 == len(word1):\n                    break\n                if word2[a] == word1[indexOfword1]:\n                    indexOfword1 += 1\n                else:\n                    if differentReached == True:\n                        return False\n                    else:\n                        differentReached = True\n            return True\n            \n                    \n", "class Solution:\n    def isPredecessor(self, predecessorCandidate, word):\n        if len(predecessorCandidate) != len(word)-1:\n            return False\n        pWhere = 0\n        wWhere = 0\n        hasSkipped = False\n        while pWhere < len(predecessorCandidate) and wWhere < len(word):\n            if predecessorCandidate[pWhere] != word[wWhere]:\n                if hasSkipped: return False\n                hasSkipped = True\n                wWhere += 1\n            else:\n                wWhere+= 1\n                pWhere += 1\n        return True\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        predecessorDict = collections.defaultdict(list)\n        chainCountDict = collections.defaultdict(lambda: 1)\n        currentMax = 1\n        for i in range(0, len(words)):\n            for j in range(i+1, len(words)):\n                if self.isPredecessor(words[i], words[j]):\n                    predecessorDict[words[j]].append(words[i])\n                    chainCountDict[words[j]] = max(chainCountDict[words[j]], 1+chainCountDict[words[i]])\n                    currentMax = max(currentMax, chainCountDict[words[j]])\n        return currentMax\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        dp = [1] * n\n        words.sort(key=len)\n        for i in range(1, n):\n            for j in range(i):\n                if self.is_predecessor(words[i], words[j]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n        return max(dp)\n    \n    def is_predecessor(self, word1, word2):\n        if len(word1) - len(word2) != 1:\n            return False\n        i1 = 0\n        i2 = 0\n        diff = 0\n        while i1 < len(word1) and i2 < len(word2):\n            if word1[i1] == word2[i2]:\n                i1 += 1\n                i2 += 1\n            else:\n                i1 += 1\n                diff += 1\n                if diff > 1:\n                    return False\n        return True\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        if not words:\n            return 0\n        n = len(words)\n        dp = [1] * n\n        for i in range(n):\n            for j in range(i):\n                if self.is_predecessor(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n\n        return max(dp)\n\n    def is_predecessor(self, str1, str2):\n        if len(str1)+1 != len(str2):\n            return False\n        cnt = 0\n        n = len(str1)\n        l1, l2 = 0, 0\n        while l1 < n and l2 < n + 1:\n            if cnt > 1:\n                return False\n\n            if str1[l1] != str2[l2]:\n                l2 += 1\n                cnt += 1\n            else:\n                l1 += 1\n                l2 += 1\n\n        return l1 == l2 or cnt == 1\n\n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        words.sort(key=len)\n        f = [1] * n\n        \n        def ispre(w1, w2):\n            if len(w1) != len(w2) - 1:\n                return False\n            \n            it = iter(w2)\n            return all(c in it for c in w1)\n        \n        res = 1\n        for i in range(1, n):\n            for j in range(i):\n                if ispre(words[j], words[i]):\n                    #print(words[j], words[i])\n                    f[i] = max(f[i], f[j] + 1)\n            res = max(res, f[i])\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        \n        def helper(a,b):\n            i,j = 0,0\n            diff = 0\n            while(i<len(a) and j<len(b)):\n                \n                if a[i] == b[j]:\n                    i+=1\n                    j+=1\n                else:\n                    i+=1\n                    diff+=1\n            if i<len(a):\n                diff+=(len(a)-i)\n            if j<len(b):\n                diff+=(len(b)-j)\n                            \n            if diff>1:\n                return False\n            else:\n                return True\n                    \n        dp = [1]*(len(words))\n        words = sorted(words,key=len)\n        \n        for i in range(len(words)):\n            for j in range(i):\n                if len(words[i])-len(words[j]) == 1 and helper(words[i],words[j]):\n                    dp[i] = max(dp[i],dp[j]+1)\n        print(dp)     \n        return max(dp)\n                    \n        \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # Sorting words by length is necessary\n        words.sort(key = lambda x: len(x))\n        max_len = [1] * len(words)\n        res = 1\n        for i in range(len(words) - 1):\n            for j in range(i, len(words)):\n                if self.isPredecessor(words[i], words[j]):\n                    max_len[j] = max(max_len[i] + 1, max_len[j])\n                    res = max(res, max_len[j])\n        return res\n    \n    # Use this function to check whether s1 is a predecessor of s2\n    def isPredecessor(self, s1, s2):\n        # Corner case:\n        if len(s2) - len(s1) != 1:\n            return False\n        # Use flag to record whether difference between s1 and s2 is found\n        flag = 0\n        i, j = 0, 0\n        while i < len(s1) and j < len(s2):\n            if s1[i] == s2[j]:\n                i += 1\n                j += 1\n            elif flag == 0:\n                flag = 1\n                j += 1\n            else:\n                return False\n        return True\n    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def chain(w1, w2):                         # check if w1 is a chain to w2\n            m, n = len(w1), len(w2)\n            if abs(m-n) != 1: return False\n            i, j, one = 0, 0, 1\n            while i < m and j < n:\n                if w1[i] == w2[j]: i, j = i+1, j+1\n                elif one: one, i = 0, i+1\n                else: return False    \n            return True\n                    \n        if not words: return 0\n        words.sort(key=lambda x: len(x))\n        n = len(words)\n        dp = [1] * n\n        ans = 1\n        for i in range(n):\n            for j in range(i): # visited all previous words[j] to check if dp[i] can reach a longer chain\n                if chain(words[i], words[j]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n            ans = max(ans, dp[i])\n        return ans        \n#https://blog.csdn.net/JamieLuo/article/details/106486186?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-2.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-2.add_param_isCf\n#\u5148\u628a\u6240\u6709\u7684words\u6309\u7167\u957f\u5ea6\u8fdb\u884csort\n#dp[i]\uff1a\u5305\u542b\u7b2ci\u4e2a\u5355\u8bcd\u5728\u5185\u7684\u6700\u957f\u94fe\n#dp[i] = max(dp[j]) + 1\uff0c\u5176\u4e2dj<i\u4e14words[j]\u662fwords[i]\u7684\u524d\u7f00\n#\u53e6\u5916\uff0c\u5728\u5224\u65ad\u662f\u5426\u662f\u524d\u7f00\u65f6\uff1a\uff081)pre\u4e00\u5b9a\u662fword\u7684\u957f\u5ea6-1\uff1b\uff082)\u904d\u5386\u4e24\u8005\uff0c\u4e24\u8005\u5e94\u8be5\u53ea\u6709\u4e00\u4e2a\u5b57\u6bcd\u4e0d\u540c\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        words.sort(key=len)\n        f = [1] * n\n        \n        def ispre(w1, w2):\n            if len(w1) != len(w2) - 1:\n                return False\n            l1, l2 = sorted(w1), sorted(w2)\n            i = j = 0\n            diff = False\n            while i < len(l1) and j < len(l2):\n                if l1[i] != l2[j]:\n                    if not diff:\n                        diff = True\n                        j += 1\n                        continue\n                    else:\n                        return False\n                i += 1\n                j += 1\n            return True\n        \n        res = 1\n        for i in range(1, n):\n            for j in range(i):\n                if ispre(words[j], words[i]):\n                    #print(words[j], words[i])\n                    f[i] = max(f[i], f[j] + 1)\n            res = max(res, f[i])\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words: return 0\n        def chain(w1, w2):\n            m, n = len(w1), len(w2)\n            if abs(m-n) != 1: return False\n            i, j, one = 0, 0, 1\n            while i < m and j < n:\n                if w1[i] == w2[j]: i, j = i+1, j+1\n                elif one: one, i = 0, i+1\n                else: return False    \n            return True\n                    \n        words.sort(key=lambda x: len(x))\n        n = len(words)\n        dp = [1] * n\n        ans = 1\n        for i in range(n):\n            for j in range(i):\n                if chain(words[i], words[j]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n            ans = max(ans, dp[i])\n        return ans        ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        ##do DP, DP[i] = length of longest possible word chain ending at words[i]\n        \n        words = sorted(words, key= lambda x: len(x))\n        # print(words)\n        DP = [0 for i in words]\n        \n        max_len = 0\n        for i in range(len(words)):\n            length = []\n            for j in range(1,i+1):\n                if len(words[i-j])< len(words[i])-1:\n                    break\n                else:\n                    if len(words[i-j]) == len(words[i])-1:\n                        if self.check(words[i-j], words[i]) == True:\n                            length.append(DP[i-j])\n            if length:\n                DP[i] = max(length)+1\n            else:\n                DP[i] = 1\n        # print(DP)     \n        return max(DP)\n    \n    def check(self, word1, word2):\n        ##if word1 + 1 character = word2 return true else return false\n        val = 0\n        # print(word1, word2)\n        for i in range(len(word1)):\n            if word1[i]!=word2[i]:\n                if val==0:\n                    word2 = word2[:i] + word2[i+1:]\n                    # print(i)\n                    # print(word1, word2)\n                    # if word1[i]!=word2[i]:\n                    #     return False\n                    return word1 == word2\n                    \n                if val==1:\n                    return False\n                continue\n        return True", "import collections\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def chain(w1, w2):                         # check if w1 is a chain to w2\n            m, n = len(w1), len(w2)\n            if abs(m-n) != 1: return False\n            i, j, one = 0, 0, 1\n            while i < m and j < n:\n                if w1[i] == w2[j]: i, j = i+1, j+1\n                elif one: one, i = 0, i+1\n                else: return False    \n            return True\n                    \n        if not words: return 0\n        words.sort(key=lambda x: len(x))\n        n = len(words)\n        dp = [1] * n\n        ans = 1\n        for i in range(n):\n            for j in range(i):                     # visited all previous words[j] to check if dp[i] can reach a longer chain\n                if chain(words[i], words[j]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n            ans = max(ans, dp[i])\n        return ans   ", "class Solution:\n    def longer_by_one(self,word1,word2):\n        if len(word2) - len(word1) != 1:\n            return False\n        j=0\n        count = 0\n        for i in range(len(word2)):\n            if i < len(word2) and j<len(word1) and word2[i]!=word1[j]:\n                count+=1\n                if count>1:\n                    return False\n                continue\n            j+=1 \n            \n        if i == len(word2) -1 and j== len(word1) and count ==1:\n            return True\n        elif i == len(word2) - 1 and j>= len(word1) and count == 0:\n            return True\n        else:\n            return False\n            \n    \n    def longestStrChain(self, words: List[str]) -> int:\n        dp =  [1] * len(words)\n        words = sorted(words, key = lambda x: len(x))\n        for i in range(1,len(words)):\n            for j in range(0,i):\n                if self.longer_by_one(words[j],words[i]) == True:\n                    dp[i] = max(dp[i],dp[j]+1)\n        for i in range(len(dp)):\n            print((words[i],dp[i]))\n        return max(dp)\n", "from collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        words=sorted(words,key=lambda x:len(x))\n        \n        # hashMap=defaultdict(list)\n        # for i in range(len(words)-1,-1,-1):\n        #     for j in range(i):\n        #         if self.isPred(words[j],words[i]):\n        #             hashMap[i].append(j)\n                    \n        # dp=[1 for _ in range(len(words))]\n        # res=1\n        # for k in range(1,len(words)):\n        #     for index in hashMap[k]:\n        #         dp[k]=max(dp[k],dp[index]+1)\n        #     res=max(res,dp[k])\n        \n        dp=[1 for _ in range(len(words))]\n        res=1\n        \n        for i in range(1,len(words)):  \n            for j in range(i):\n                if len(words[j])+1==len(words[i]) and self.isPred(words[j],words[i]):\n                    dp[i]=max(dp[i],dp[j]+1)\n            res=max(res,dp[i])   \n            \n        return res\n            \n \n    \n    def isPred(self,word1,word2):\n        if len(word1)+1!=len(word2):\n            return False\n        \n        p1=0\n        p2=0\n        degree=0\n        \n        while p1<len(word1) and p2<len(word2):\n            if word1[p1]==word2[p2]:\n                p1+=1\n                p2+=1\n                continue\n            else:\n                degree+=1\n                p2+=1\n               \n        return degree<2\n\n                \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        result = 1\n\n        for word in sorted(words, key=lambda x: -len(x)):\n            dp[word] = 1\n\n            for i in range(len(word)+1):\n                for c in 'abcdefghijklmnopqrstuvwxyz':\n                    next_word = word[:i] + c + word[i:]\n\n                    if next_word in dp:\n                        dp[word] = max(dp[word], dp[next_word] + 1)\n                        result = max(result, dp[word])\n\n        return result", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        by_length = collections.defaultdict(set)\n        for word in words:\n            by_length[len(word)].add(word)\n\n        longest = 1\n        seen = {*()} # set()\n        mx = len(by_length)\n        mn = min(by_length)\n        \n        # in descending order\n        for length in sorted(by_length, reverse=True):\n            if length == mn: return 1\n            if length - mn < longest:\n                break\n            for word in by_length[length]:\n                if length - mn < longest:\n                    break\n                if word in seen:\n                    continue\n                stk = [(word, length, 1)]\n                while stk:\n                    word, k, n = stk.pop()\n                    seen.add(word)\n                    if n > longest:\n                        longest = n\n                    for i in range(k):\n                        pre = word[:i] + word[i+1:]\n                        if pre not in seen and pre in by_length[k-1]:\n                            stk.append((pre, k-1, n+1))\n                if longest == mx:\n                    return longest\n\n        return longest   ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        longestchain = defaultdict(int)\n        words.sort(key=len, reverse=True)\n        for word in words:\n            for i in range(len(word)):\n                pred = word[:i] + word[i + 1:]\n                longestchain[pred] = max(longestchain[pred], 1 + longestchain[word])\n        return max(longestchain.values()) \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # Note: order does not matter for this problem\n        words = sorted(words, key=lambda word: len(word))\n        # Once we've sorted words by length, we need an efficient way to\n        # check if a longer word can be generated from a shorter word\n        # We can simply do a char by char comparison which is O(W), where W \n        # is the maximum length of a word\n        # You have to do this for all strings of length 1 less than current string's length\n        # If you find a match, then increment the dp value\n        n = len(words)\n        if n == 1:\n            return 1\n        \n        ans = 1\n        # dp[i] is the length of the longest chain ending at i\n        dp = [1]*n\n        \n        # Check if string at i can be generated from string at j\n        def match(i, j):\n            # This function assumes that len(words[i]) - len(words[j]) == 1\n            idx_i = 0\n            idx_j = 0\n            skipped = False\n            while idx_j < len(words[j]):\n                if words[i][idx_i] != words[j][idx_j]:\n                    if skipped:\n                        return False\n                    skipped = True\n                    idx_i += 1\n                else:\n                    idx_i += 1\n                    idx_j += 1\n            return True\n        \n        for i in range(1, n):\n            for j in range(i-1, -1, -1):\n                if len(words[i]) - len(words[j]) > 1:\n                    break\n                elif len(words[i]) - len(words[j]) == 1:\n                    if match(i, j):\n                        dp[i] = max(dp[i], dp[j] + 1)\n                        ans = max(ans, dp[i])\n                else:\n                    pass\n            \n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = sorted(words, key=lambda w: len(w))\n        dp = [None] * len(words)\n        dp[0] = 1\n        for i in range(1, len(words)):\n            maxi = 1\n            for j in list(range(0,i))[::-1]:\n                # print(j)\n                if(self.check(words[j], words[i]) and dp[j]+1 > maxi):\n                    maxi = dp[j] +1\n            dp[i] = maxi\n        # print(dp)\n        return max(dp)\n    def check(self, chain, word):\n        if(len(chain)+1 != len(word)):\n            return False\n        i=0\n        j=0\n        Flag = False\n        while(i<len(chain) and j<len(word)):\n            if(chain[i] == word[j]):\n                i+=1\n                j+=1\n            elif(chain[i]!=word[j] and not Flag):\n                j+=1\n                Flag = True\n            else:\n                return False\n        return True\n", "def chain(w1, w2):                         # check if w1 is a chain to w2\n    m, n = len(w1), len(w2)\n    if abs(m-n) != 1: return False\n    i, j, one = 0, 0, 1\n    while i < m and j < n:\n        if w1[i] == w2[j]: i, j = i+1, j+1\n        elif one: one, i = 0, i+1\n        else: return False    \n    return True\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = [1]*(len(words))\n        dp[0] = 1\n        words.sort(key=lambda x: len(x))\n        for i in range(1, len(words)):\n            for j in range(0,i):\n                if chain(words[i], words[j]):\n                    # print(dp[i],dp[j]+1)\n                    dp[i] = max(dp[i], dp[j]+1)\n        # print(dp)\n        return max(dp)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        # self.memo = defaultdict(bool)\n        def isPred(p,q,words):\n            # return if words[p] is a predecessor of words[q]\n            # if (p,q) in self.memo:\n                # return self.memo[(p,q)]\n            w1 = words[p]\n            w2 = words[q]\n            n2 = len(w2)\n            res = False\n            for i in range(n2):\n                if w1 == w2[0:i]+w2[i+1:]:\n                    res = True\n            return res\n        \n        n = len(words)\n        \n        # dpA = [1]*n# dp[i] is the longest length of word chain consisting of dp[i]\n        # for i in range(n):\n        #     cur = 1\n        #     for j in range(i):\n        #         if isPred(j,i,words):\n        #            cur = max(cur,dpA[j]+1)\n        #     dpA[i] = cur\n        # print(dpA)\n        \n        dpR = [1]*n\n        wR = sorted(words,key=len)\n        # print(wR)\n        for i in range(n):\n            cur = 1\n            for j in range(i):\n                n1 = len(wR[j])\n                n2 = len(wR[i])\n                if n2-n1!=1:\n                    continue\n                if isPred(j,i, wR):\n                    cur = max(cur,dpR[j]+1)\n            dpR[i] = cur\n        # print(dpR)\n        \n        \n        \n        return max(dpR)\n            \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        words.sort(key = len)\n        print(words)\n        solutions = []\n        \n        numWords = len(words)\n        \n        for i in range(numWords):   \n            self.getSequences(words[i+1:], len(words[i]) + 1, [words[i]], words[i], solutions)\n        \n        maxSize = 0\n        \n        for s in solutions:\n            maxSize = max(maxSize, len(s))\n        \n        return maxSize\n        \n    def getSequences(self, words, targetLength, currSequence, lastWord, solutions):\n        \n        numWords = len(words)\n        for i in range(numWords):\n            if len(words[i]) == targetLength:\n                if self.isPredecessor(lastWord, words[i]):\n                    newCurrSequence = currSequence[:]\n                    newCurrSequence.append(words[i])\n                    self.getSequences(words[i+1:], targetLength + 1, newCurrSequence, words[i], solutions)\n                    \n            elif len(words[i]) > targetLength:\n                break\n                \n        if len(solutions) > 0:\n            if len(solutions[0]) < len(currSequence):\n                solutions[0] = currSequence\n        else:\n            solutions.append(currSequence)\n        return\n        \n    def isPredecessor(self, word1, word2):\n        \n        numLetters1 = len(word1)\n        numLetters2 = len(word2)\n        \n        if numLetters2 - numLetters1 != 1:\n            return False\n        \n        p1 = 0\n        p2 = 0\n        count = 0\n        \n        while p1 < numLetters1:\n            if word1[p1] == word2[p2]:\n                p1 += 1\n                p2 += 1\n            elif count == 1:\n                return False\n            else:\n                count += 1\n                p2 += 1\n                \n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def check(w1, w2):\n            idx = 0\n            \n            for i in range(len(w2)):\n                if w2[i]==w1[idx]:\n                    idx += 1\n                \n                if idx==len(w1):\n                    return True\n            \n            return False\n        \n        n = len(words)\n        words.sort(key=lambda w: len(w))\n        G = [[] for _ in range(n)]\n        \n        for i in range(n):\n            for j in range(i+1, n):\n                if len(words[j])-len(words[i])>1:\n                    break\n                \n                if len(words[j])-len(words[i])==1 and check(words[i], words[j]):\n                    G[i].append(j)\n                \n        def rec(v):\n            if memo[v]!=-1:\n                return memo[v]\n            \n            res = 1\n            \n            for nv in G[v]:\n                res = max(res, rec(nv)+1)\n            \n            memo[v] = res\n            return res\n    \n        memo = [-1]*n\n        ans = 0\n        \n        for i in range(n):\n            ans = max(ans, rec(i))\n        \n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        words.sort(key = len)\n        print(words)\n        solutions = []\n        \n        numWords = len(words)\n        \n        for i in range(numWords):   \n            self.getSequences(words[i+1:], len(words[i]) + 1, [words[i]], words[i], solutions)\n        \n        maxSize = 0\n        \n        for s in solutions:\n            maxSize = max(maxSize, len(s))\n        \n        return maxSize\n        \n    def getSequences(self, words, targetLength, currSequence, lastWord, solutions):\n        \n        numWords = len(words)\n        for i in range(numWords):\n            if len(words[i]) == targetLength:\n                if self.isPredecessor(lastWord, words[i]):\n                    newCurrSequence = currSequence[:]\n                    newCurrSequence.append(words[i])\n                    self.getSequences(words[i+1:], targetLength + 1, newCurrSequence, words[i], solutions)\n                    \n            elif len(words[i]) > targetLength:\n                break\n        solutions.append(currSequence)\n        return\n        \n    def isPredecessor(self, word1, word2):\n        \n        numLetters1 = len(word1)\n        numLetters2 = len(word2)\n        \n        if numLetters2 - numLetters1 != 1:\n            return False\n        \n        p1 = 0\n        p2 = 0\n        count = 0\n        \n        while p1 < numLetters1:\n            if word1[p1] == word2[p2]:\n                p1 += 1\n                p2 += 1\n            elif count == 1:\n                return False\n            else:\n                count += 1\n                p2 += 1\n                \n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        longestchain = defaultdict(int)\n        for word in sorted(words, key=len, reverse=True):\n            for i in range(len(word)):\n                pred = word[:i] + word[i + 1:]\n                longestchain[pred] = max(longestchain[pred], 1 + longestchain[word])\n        return max(longestchain.values()) \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        words.sort(key = len)\n        print(words)\n        solutions = []\n        \n        numWords = len(words)\n        \n        for i in range(numWords):   \n            self.getSequences(words[i+1:], len(words[i]) + 1, [words[i]], words[i], solutions)\n        \n            \n        if len(solutions) > 0:\n            return len(solutions[0])\n        else:\n            return 0\n        \n    def getSequences(self, words, targetLength, currSequence, lastWord, solutions):\n        \n        numWords = len(words)\n        for i in range(numWords):\n            if len(words[i]) == targetLength:\n                if self.isPredecessor(lastWord, words[i]):\n                    newCurrSequence = currSequence[:]\n                    newCurrSequence.append(words[i])\n                    self.getSequences(words[i+1:], targetLength + 1, newCurrSequence, words[i], solutions)\n                    \n            elif len(words[i]) > targetLength:\n                break\n                \n        if len(solutions) > 0:\n            if len(solutions[0]) < len(currSequence):\n                solutions[0] = currSequence\n        else:\n            solutions.append(currSequence)\n        return\n        \n    def isPredecessor(self, word1, word2):\n        \n        numLetters1 = len(word1)\n        numLetters2 = len(word2)\n        \n        if numLetters2 - numLetters1 != 1:\n            return False\n        \n        p1 = 0\n        p2 = 0\n        count = 0\n        \n        while p1 < numLetters1:\n            if word1[p1] == word2[p2]:\n                p1 += 1\n                p2 += 1\n            elif count == 1:\n                return False\n            else:\n                count += 1\n                p2 += 1\n                \n        return True", "class Solution:\n    def check(self, word1, word2) -> bool:\n        if len(word1)+1 != len(word2):\n            return False\n        for i in range(len(word1)+1):\n            if i < len(word1) and word1[i] == word2[i]:\n                continue\n            else:\n                word2 = word2[:i] + word2[i+1:]\n                return word1 == word2\n            \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        # print(words)\n        output = [0 for i in range(len(words))]\n        for j in range(-1,-len(words)-1,-1):\n            # print(f\\\"{j} and {output}\\\")\n            temp_len = 1\n            k = j+1\n            while k <= -1:\n                if temp_len < output[k]+1:\n                    # print(f\\\"{words[j]} and {words[k]} and {output}\\\")\n                    if self.check(words[j], words[k]):\n                        temp_len = output[k]+1\n                k += 1\n            output[j] = temp_len\n        return max(output)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        li = {word:1 for word in words} \n        words.sort(key=len) \n        ans = 1\n        for word in words:\n            for  i in range(len(word)):\n                new  = word[:i] + word[i+1:]\n                \n                if new in words:\n                    #print(f\\\"{new} is in {word}\\\")\n                    #print(f\\\" {li[word]}  and for new is {li[new] + 1 }\\\")\n                    if li[word] < li[new] + 1:\n                       # print(f\\\" {li[word]}  and for new is {li[new]}\\\")\n                        li[word] = li[new] + 1\n                        if li[word] > ans:\n                                ans = li[word]\n        return ans\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        longestchain = defaultdict(int)\n        for word in sorted(words, key=len):\n            for i in range(len(word)):\n                longestchain[word] = max(longestchain[word[:i] + word[i+1:]] + 1, longestchain[word])\n        return max(longestchain.values()) \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = [0]*len(words)\n        \n        words.sort(key=lambda x: len(x))\n        \n        \n        def predecessor(a, b):\n            if len(a) == len(b):\n                return False\n            diff = 0\n            i = 0\n            j = 0\n            while i <len(a) and j<len(b):\n                if a[i]!=b[j]:\n                    diff += 1\n                    if diff>=2:\n                        return False\n                    i+=1\n                else:\n                    i+=1\n                    j+=1\n            return True\n        for i, word in enumerate(words):\n            dp[i] = 1\n            for j in range(i-1, -1,-1):\n                if len(words[i]) - len(words[j])>=2:\n                    break\n                if predecessor(words[i], words[j]):\n                    dp[i] = max(dp[i], dp[j]+1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_seq(word1, word2):\n            if len(word2)!=len(word1)+1:\n                return False\n            L=len(word2)\n            for idx in range(L):\n                if word1==word2[:idx]+word2[idx+1:]:\n                    return True\n            return False\n        \n        L=len(words)\n        dp=[1 for w in words]\n        words=sorted(words, key=lambda x:len(x))\n        for idx in range(L):\n            word2=words[idx]\n            for j in range(idx):\n                word1=words[j]\n                if is_seq(word1, word2):\n                    dp[idx]=max(dp[idx], dp[j]+1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        dp = [1 for _ in words]\n        for start in range(len(words)):\n            for end in range(start-1, -1, -1):\n                if len(words[end]) < len(words[start])-1:\n                    break\n                if predecessor(words[start], words[end]):\n                    dp[start] = max(dp[start], 1 + dp[end])\n        return max(dp)\n    \ndef predecessor(word, candidate):\n    if len(word) != len(candidate)+1:\n        return False\n    j = 0\n    for i, c in enumerate(word):\n        if i > j + 1 or j == len(candidate):\n            break\n        if c == candidate[j]:\n            j += 1\n    return j == len(candidate)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words: return 0\n        def chain(w1, w2):\n            m, n = len(w1), len(w2)\n            if abs(m-n) != 1: return False\n            i, j, one = 0, 0, 1\n            while i < m and j < n:\n                if w1[i] == w2[j]: i, j = i+1, j+1\n                elif one: one, i = 0, i+1\n                else: return False    \n            return True\n                    \n        words.sort(key=lambda x: len(x))\n        n = len(words)\n        dp = [1] * n\n        ans = 1\n        for i in range(n):\n            for j in range(i):\n                if chain(words[i], words[j]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n                if dp[i] > ans: break\n            ans = max(ans, dp[i])\n        return ans        ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        self.memo = defaultdict(bool)\n        def isPred(p,q,words):\n            # return if words[p] is a predecessor of words[q]\n            if (p,q) in self.memo:\n                return self.memo[(p,q)]\n            w1 = words[p]\n            w2 = words[q]\n            n2 = len(w2)\n            res = False\n            for i in range(n2):\n                if w1 == w2[0:i]+w2[i+1:]:\n                    res = True\n            self.memo[(p,q)] = res\n            return res\n        \n        n = len(words)\n        \n        # dpA = [1]*n# dp[i] is the longest length of word chain consisting of dp[i]\n        # for i in range(n):\n        #     cur = 1\n        #     for j in range(i):\n        #         if isPred(j,i,words):\n        #            cur = max(cur,dpA[j]+1)\n        #     dpA[i] = cur\n        # print(dpA)\n        \n        dpR = [1]*n\n        wR = sorted(words,key=len)\n        # print(wR)\n        for i in range(n):\n            cur = 1\n            for j in range(i):\n                n1 = len(wR[j])\n                n2 = len(wR[i])\n                if n2-n1!=1:\n                    continue\n                if isPred(j,i, wR):\n                    cur = max(cur,dpR[j]+1)\n            dpR[i] = cur\n        # print(dpR)\n        \n        \n        \n        return max(dpR)\n            \n            \n", "def predecessor(word, candidate):\n    if len(word) != len(candidate)+1:\n        return False\n    j = 0\n    for i, c in enumerate(word):\n        if i > j + 1 or j == len(candidate):\n            break\n        if c == candidate[j]:\n            j += 1\n    return j == len(candidate)\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        dp = [1 for _ in words]\n        for start in range(len(words)):\n            for end in range(start-1, -1, -1):\n                if len(words[end]) < len(words[start])-1:\n                    break\n                if predecessor(words[start], words[end]):\n                    dp[start] = max(dp[start], 1 + dp[end])\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words=sorted(words,key=lambda x:len(x))\n        def helper(w1,w2):\n            if len(w2)-len(w1)!=1:return False\n            i,j=0,0\n            while i<len(w1) and j<len(w2):\n                if w1[i]==w2[j]:\n                    i+=1\n                j+=1\n            return i==len(w1)\n        n=len(words)\n        dp=[1 for i in range(n)]\n        for i in range(n):\n            for j in range(i):\n                if helper(words[j],words[i]):\n                    dp[i]=max(dp[i],dp[j]+1)\n        return max(dp)\n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        \n        # words=sorted(words,key=lambda x:len(x))\n        # def ccmp(a,b):\n        #     if len(b)-len(a)!=1:\n        #         return False\n        #     i,j=0,0\n        #     while i<len(a) and j <len(b):\n        #         if a[i]==b[j]:\n        #             i+=1\n        #             j+=1\n        #         else:\n        #             j+=1\n        #     return i==len(a)\n        # n=len(words)\n        # dp=[1 for i in range(n)]\n        # for i in range(1,n):\n        #     for j in range(i):\n        #         if len(words[i])-len(words[j])==1:\n        #             if ccmp(words[j],words[i]): \n        #                 dp[i]=max(dp[i],dp[j]+1)\n        # ans=0\n        # for i in range(n):\n        #     ans=max(ans,dp[i])\n        # return ans\n                    \n                \n                    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def pred(a, b):\n            if len(a) == len(b) or len(a) - len(b) > 1:\n                return False\n            \n            diff = 0\n            i = 0\n            j = 0\n            while i < len(a):\n                if a[i] == b[j]:\n                    i+=1\n                    j+=1\n                else:\n                    diff+=1\n                    if diff > 1:\n                        return False\n                    j+=1\n                    \n            return True\n        \n        if not words:\n            return 0\n        \n        dp = [0 for w in words]\n        ret = 0\n        \n        words.sort(key=len)\n        \n        for i in range(len(words)):\n            dp[i] = 1\n            \n            for j in range(i):\n                if ((len(words[i]) - len(words[j]) <= 1) and pred(words[j], words[i])):\n                    dp[i] = max(dp[i], dp[j]+1)\n            ret = max(ret, dp[i])\n        \n        return ret", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        from collections import defaultdict, deque\n        hash_map = defaultdict(list)\n        visited = {}\n        max_len = 0\n        q = deque()\n        for char in words:\n            if len(char) >1:\n                neighbors = [char[:i] + char[i+1:] for i in range(len(char))]\n                for n in neighbors:\n                    hash_map[n].append(char)\n            hash_map[char].append(char)\n\n        words.sort(key=len)\n        for word in words:\n            q.appendleft((word, 1))\n\n\n        while q:\n            char, count = q.pop()\n            if char not in visited and char in hash_map:\n                max_len = max(max_len, count)\n                for n in hash_map[char]:\n                    q.append((n, count + 1))\n\n            visited[char] = 1\n\n        return max_len\n                    \n\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPredecessor(a, b):\n            if len(a) != len(b) -1 or len(b) == 1:\n                return False\n            for i in range(len(b)):\n                tmp = b[:i] + b[i+1:]\n                if a == tmp:\n                    return True\n            return False\n        words.sort(key=len)\n        dp = [1] * (len(words))\n        for i in range(len(dp)):\n            for j in range(i-1, -1, -1):\n                if isPredecessor(words[j], words[i]):\n                    dp[i] = max(dp[j] +1, dp[i])\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # longest path in a specially constructed DAG\n        dp = [0 for i in range(len(words))]\n        ans = 0\n        words = sorted(words, key=lambda x: len(x))\n        for i in range(len(words)):\n            for j in range(i):\n                if self.prev(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n                    ans = max(ans, dp[i])\n        \n        return ans + 1\n    \n    def prev(self, word_1, word_2):\n        len_1, len_2 = len(word_1), len(word_2)\n        if len_1 + 1 != len_2:\n            return False\n        \n        i = j = 0\n        while i < len_1 and j < len_2:\n            if word_1[i] == word_2[j]:\n                i += 1\n            j += 1\n        if i == len_1:\n            return True\n        else:\n            return False", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n\n        words.sort(key=len)\n        print(words)\n        sequence = collections.defaultdict(list)\n        dp = [1]*len(words)\n        \n        for i in range(len(words)):\n            for j in range(0, i):\n                predecessor = self.checkPredecessor(words[j], words[i])\n                if predecessor:\n                    sequence[words[i]].append(words[j])\n                    dp[i] = max(dp[j] + 1, dp[i])\n                    \n        print(sequence)\n        print(list(zip(words, dp)))\n        return(max(dp))\n                \n    def checkPredecessor(self, word1, word2):\n        if len(word2)-len(word1) > 1:\n            return False\n        elif len(word1) == len(word2):\n            return False\n        \n        i = j = 0\n        diff = False\n        while i < len(word1):\n        \n            if word1[i] == word2[j]:\n                i += 1\n                j += 1\n            elif not diff:\n                diff = True\n                j += 1\n            else:\n                return False\n        \n        if i == len(word1) and j < len(word2) and diff:\n            return False\n        \n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = sorted(words, key=len)\n        def onediff(word1, word2):\n            if len(word1) + 1 != len(word2) : return False\n            for i in range(len(word2)):\n                if word2[:i] + word2[i+1:] == word1 : \n                    return True\n            return False\n        dp = [1] * len(words)\n        for i in range(len(words)):\n            for j in range(i):\n                if onediff(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j]+1)\n        return max(dp)\n", "from collections import Counter\n\nclass Solution:\n    def is_one_away(self, str_1, str_2):\n        c1 = Counter(str_1)\n        c2 = Counter(str_2)\n        diff = 0\n        for k, v in c2.items():\n            diff += v - c1.get(k, 0)\n            if diff > 1:\n                return False\n        \n        for k in c1:\n            if k not in c2:\n                return False\n        \n        return True\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        sorted_words = sorted([''.join(sorted(w)) for w in words], key=lambda x: len(x))\n        dp = [1] * len(words)\n        \n        for i in range(len(sorted_words)-1,-1,-1):\n            for j in range(i-1, -1, -1):\n                if len(sorted_words[i]) - len(sorted_words[j]) == 0:\n                    continue\n                \n                if len(sorted_words[i]) - len(sorted_words[j]) > 1:\n                    break\n                    \n                if self.is_one_away(sorted_words[j], sorted_words[i]):\n                    dp[j] = max(1+dp[i], dp[j])\n                    \n                \n            \n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(x, y):\n            if len(x) != len(y) - 1:\n                return False\n            \n            i = 0\n            j = 0\n            while i < len(x) and j < len(y):\n                if x[i] == y[j]:\n                    i += 1\n                    j += 1\n                else:\n                    j += 1\n                    \n            if i == len(x):\n                return True\n            return False\n        \n        words = sorted(words, key=lambda x: len(x))\n        n = len(words)\n        dp = [1] * n\n        for i in range(1, n):\n            for j in range(i):\n                if is_predecessor(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n        \n        return max(dp)\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda w: len(w))\n        \n        word_chains = {w: 1 for w in words}\n        \n        # intentionally min length to max length\n        for word in words:\n            for i in range(len(word)):\n                sub_word = word[:i] + word[i+1:]\n                if sub_word in words:\n                    word_chains[word] = max(word_chains[sub_word] + 1, word_chains[word])\n        \n        return max(word_chains.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        res = 1\n        for word in sorted(words,key = len):\n            for i in range(len(word)):\n                # print(word[:i])\n                if word[:i] + word[i+1:] in words:\n                    dp[word] = dp.get(word[:i]+word[i+1:],1) + 1\n                    res = max(res,dp[word])\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n\n        if not words:\n            return 0 \n\n        words.sort(key = lambda x: len(x)) #O(nlogn)\n        n = len(words)\n        dp = [1 for i in range(n)]\n\n        for i in range(1, n): # O(n^2)\n            for j in range(i):\n                if self.is_predecessor(words[j], words[i]): # O(k)\n                    dp[i] = max(dp[i], dp[j] + 1)\n\n        return max(dp)\n    \n    def is_predecessor(self, word1, word2):\n\n        if len(word1) + 1 != len(word2):\n            return False\n\n        i, j = 0, 0\n        while i < len(word1) and j < len(word2):\n            if word1[i] == word2[j]:\n                i += 1\n                j += 1\n            else:\n                j += 1\n\n        return i == len(word1)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        words = [(len(word), word) for word in words]\n        words.sort()\n        words = [word[1] for word in words]\n        dp = [1 for i in range(n)]\n        \n        for i in range(n):\n            for j in reversed(list(range(i))):\n                if len(words[j]) < len(words[i]) - 1:\n                    break\n                \n                if len(words[j]) == len(words[i]):\n                    continue\n\n                if self.check(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j] + 1)\n    \n        return max(dp)\n    \n    def check(self, s1, s2):\n        i, j = 0, 0\n        count = 0\n        while i < len(s1) and j < len(s2):\n            if s1[i] == s2[j]:\n                i += 1\n                j += 1\n            else:\n                j += 1\n                count += 1\n            \n        return i == len(s1)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def pre(word2, word):\n            if len(word2) + 1 == len(word):\n                for i in range(len(word)):\n                    if word[:i]+word[i+1:] == word2:\n                        return True\n            return False\n   \n        words = sorted(words, key=lambda x: -len(x))\n        best = 0\n        \n        n = len(words)\n        length = [0]*n\n        \n        for i in range(n):\n            for j in range(i+1,n):\n                if pre(words[j], words[i]):\n                    # print('pre', word2, word)\n                    length[j] = max(length[j], length[i] + 1)\n                    best = max(best, length[j])    \n                    \n        # print(length)\n        \n        return best+1", "def isPredecessor(src, dst):\n    nsrc = len(src)\n    ndst = len(dst)\n    if nsrc+1 != ndst:\n        return False\n    \n    i = 0\n    while i < nsrc:\n        if src[i] == dst[i]:\n            i += 1\n            continue\n        else:\n            return src[i:] == dst[i+1:]\n    \n    return True\n        \nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        mem_len = [-1 for _ in range(len(words))]\n        \n        def search(i):\n            if mem_len[i] != -1:\n                return mem_len[i]\n            \n            ans = 1\n            for j in range(i+1, len(words)):    \n                if isPredecessor(words[i], words[j]):\n                    mem_len[j] = search(j)\n                    ans = max(ans, mem_len[j]+1)\n                    \n            mem_len[i] = ans\n            return ans\n            \n        for i in range(len(words)):\n            search(i)\n\n        return max(mem_len)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        l = [1 for i in range(len(words))]\n        words.sort(key = lambda x:len(x))\n        res = [[i] for i in words]\n        # print(l,res)\n        for i in range(1,len(words)):\n            for j in range(i):\n                if len(words[j])+1==len(words[i]):\n                    x = {}\n                    for a in words[j]:\n                        if a in x:\n                            x[a]+=1\n                        else:\n                            x[a]=1\n                    ctr = 0\n                    for a in words[i]:\n                        if a not in x:\n                            ctr+=1\n                        elif x[a]==0:\n                            ctr+=1\n                        else:\n                            x[a]-=1\n                    if ctr==1 and l[i]<(l[j]+1):\n                        res[i] = [i for i in res[j]]\n                        res[i].append([words[i]])\n                        l[i] = l[j]+1\n        return max(l)\n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = sorted(words, key=lambda w: len(w))\n        total = len(words)\n        count = [1 for _ in range(total)]\n        for i in range(1, total):\n            for j in range(i):\n                if self.predecessor(words[j], words[i]) and count[i] < count[j] + 1:\n                    count[i] = count[j] + 1\n        # print(count)\n        return max(count)\n    \n    def predecessor(self, word1, word2):\n        if len(word2) != len(word1) + 1:\n            return False\n        for i in range(len(word2)):\n            subword = word2[:i] + word2[i+1:]\n            if subword == word1:\n                return True\n        return False", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x: len(x))\n        N = len(words)\n        self.longest = [None]*N\n        max_len = 1\n        for i in range(N):\n            max_len = max(max_len, self.__findLongestAfter(words, i))\n            \n        return max_len\n                                    \n                \n    def __isPredecessor(self, w1, w2):\n        if len(w2) != len(w1)+1:\n            return False\n        \n        for i in range(len(w2)):\n            if (w2[:i]+w2[i+1:]) == w1:\n                return True\n        return False\n    \n    def __findLongestAfter(self, words: List[str], i:int) -> int:\n        if self.longest[i] is not None:\n            return self.longest[i]\n        \n        max_len = 1\n        for j in range(i+1, len(words)):\n            if self.__isPredecessor(words[i], words[j]):\n                max_len = max(max_len, self.__findLongestAfter(words, j)+1)\n                \n        self.longest[i] = max_len\n        return max_len", "class Solution:\n\n    def predecessor(self, w1, w2):\n        \n        i = 0\n\n        diffs = 0\n\n        while i<len(w1):\n            if w1[i] != w2[i]:\n                diffs = 1\n                break\n\n            i+=1\n\n        if diffs==0:\n            return True\n\n        return w1==w2[:i]+w2[i+1:]\n\n    def longestStrChain(self, words):\n\n        words = sorted(words, key=lambda x: len(x))\n\n        #print(words)\n\n        words_by_len = {}\n\n        for w in words:\n            if len(w) in words_by_len:\n                words_by_len[len(w)].append(w)\n            else:\n                words_by_len[len(w)] = [w]\n\n        #print(words_by_len)\n\n        max_lens = {}\n\n        for w in words:\n            max_lens[w] = 1\n\n        for l in words_by_len:\n\n            if l-1 in words_by_len:\n            \n                for w1 in words_by_len[l]:\n                    for w2 in words_by_len[l-1]:\n                        #print(w1, w2)\n\n                        if self.predecessor(w2, w1):\n                            max_lens[w1] = max(max_lens[w1], 1+max_lens[w2])\n\n        max_len = 0\n\n        for w in max_lens:\n            max_len = max(max_len, max_lens[w])\n\n        return max_len\n\n", "class Solution:\n    # def predecessor(self, long, short):\n    #     # print(long, short)\n    #     for i in range(len(long)):\n    #         if long[0:i] + long[i+1:] == short:\n    #             return True\n    #     return False\n    def predecessor(self, word, candidate):\n        if len(word) != len(candidate)+1:\n            return False\n        j = 0\n        for i, c in enumerate(word):\n            if i > j + 1 or j == len(candidate):\n                break\n            if c == candidate[j]:\n                j += 1\n        return j == len(candidate)\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        dp = [1 for _ in words]\n        for i in range(len(words)):\n            for j in range(i, -1, -1):\n                if len(words[i]) - len(words[j]) > 1:\n                    break\n                if self.predecessor(words[i], words[j]):\n                    # print(\\\"hi\\\")\n                    dp[i] = max(dp[i], dp[j]+1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, wordlist: List[str]) -> int:\n        wl = set(wordlist)\n        def dfs(w):\n            # base\n            if len(w) == 1:\n                return 1\n            if w in memo:\n                return memo[w]\n            # recursive\n            l = len(w)\n            depth = 0\n            for i in range(l):\n                next = w[0:i] + w[i+1:l] # substring\n                if next in wordlist:\n                    depth = max(depth, dfs(next))\n            memo[w] = depth + 1\n            return depth + 1\n\n        memo = {}\n        longest = 1\n        for word in wordlist:\n            longest = max(longest, dfs(word))\n        return longest\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = [x for x in sorted(words, key=lambda w: len(w))]\n        total = len(words)\n        count = [1 for _ in range(total)]\n        for i in range(1, total):\n            for j in range(i):\n                if self.predecessor(words[j], words[i]) and count[i] < count[j] + 1:\n                    count[i] = count[j] + 1\n        # print(count)\n        return max(count)\n    \n    def predecessor(self, word1, word2):\n        if len(word2) != len(word1) + 1:\n            return False\n        for i in range(len(word2)):\n            subword = word2[:i] + word2[i+1:]\n            if subword == word1:\n                return True\n        return False", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def helper(word_pre, word_cur):\n            if len(word_pre) - len(word_cur) != -1: return False\n            count, pre, cur = 0, 0, 0\n            while pre <= len(word_pre) and cur < len(word_cur):\n                if pre < len(word_pre) and word_cur[cur] == word_pre[pre]:\n                    pre += 1\n                else:\n                    count += 1\n                cur += 1\n            return True if count == 1 else False\n\n        dp = [1] * len(words)\n        words = sorted(words, key=len)\n        for i in range(len(words)):\n            for j in range(i):\n                if helper(words[j], words[i]) and dp[j] > dp[i] - 1:\n                    dp[i] = dp[j] + 1\n        return max(dp)\n\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x: len(x))\n        N = len(words)\n        self.longest = [None]*N\n        max_len = 1\n        for i in range(N):\n            max_len = max(max_len, self.__findLongestAfter(words, i))\n            \n        return max_len\n                                    \n                \n    def __isPredecessor(self, w1, w2):\n        if len(w2) != len(w1)+1:\n            return False\n        \n        i=j=0\n        while i < len(w1) and j < len(w2):\n            if w1[i] == w2[j]:\n                i+=1\n            j+=1\n            \n        return (i == len(w1))\n    \n    def __findLongestAfter(self, words: List[str], i:int) -> int:\n        if self.longest[i] is not None:\n            return self.longest[i]\n        \n        self.longest[i] = 1\n        len_i = len(words[i])\n        for j in range(i+1, len(words)):\n            if len(words[j]) - len_i > 1:\n                break\n                \n            if self.__isPredecessor(words[i], words[j]):\n                self.longest[i] = max(self.longest[i], self.__findLongestAfter(words, j)+1)\n                \n        return self.longest[i]", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        d = {w : 1 for w in words}\n        words.sort(key = lambda x: len(x))\n        def check(w1, w2):\n            if len(w1) <= len(w2):\n                return False\n            if len(w1) - len(w2) == 1:\n                '''for i in range(len(w1)):\n                    temp = w1[:i] + w1[i + 1:]\n                    if temp == w2:\n                        return True'''\n                i = 0\n                j = 0\n                count = 0\n                while i < len(w1) and j < len(w2):\n                    if w1[i] == w2[j]:\n                        i += 1\n                        j += 1\n                    else:\n                        i += 1\n                        count += 1\n                        \n                if count > 1:\n                    return False\n                else:\n                    return True\n                    \n            return False\n                    \n            \n            \n        \n        \n        dp = [0 for _ in range(len(words))]\n        \n        dp[0] = 1\n        res = 1\n        for i in range(1, len(words)):\n            curr_max = 0\n            for j in range(i):\n                if check(words[i], words[j]): \n                    curr_max = max(curr_max, dp[j])\n                    \n            dp[i] = curr_max + 1\n            res = max(res, dp[i])\n\n            \n        return res\n            \n", "class Solution:\n    def isPredecessor(self, word1, word2):\n        if len(word1)+1 == len(word2):\n            i = 0\n            j = 0\n            count = 0\n            while i < len(word1) and j < len(word2):\n                if word1[i] != word2[j]:\n                    count += 1\n                else:\n                    i += 1\n                j += 1\n            if count > 1:\n                return False\n            elif count == 0:\n                if len(word2) == j + 1:\n                    return True\n            else:\n                return True\n        else:\n            return False\n        \n    def memoization(self, i, words, memo):\n        if i >= len(words):\n            return 0\n        if memo[i] is not None:\n            return memo[i]\n        length = 0\n        for j in range(i+1, len(words)):\n            # if i==14:\n            #     print(words[i], words[j], self.isPredecessor(words[i], words[j]))\n            if self.isPredecessor(words[i], words[j]):\n                length = max(length, self.memoization(j, words, memo))\n        memo[i] = 1 + length\n        return memo[i]\n\n    def longestStrChain(self, words: List[str]) -> int:\n        words = sorted(words, key=len)\n        memo = [None]*len(words)\n        length = 0\n        for i in range(len(words)):\n            length = max(length, self.memoization(i, words, memo))\n        return length", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        ## return a list of lists\n        #words.sort(cmp=lambda x,y:len(x) - len(y))\n        words = sorted(words, key = lambda x: len(x))\n        #print(words)\n        dp = [1]*len(words)\n        res = 1\n        for i in range(len(words)):\n            for j in range(0,i):\n                ## compare word[j] -> word[i]\n                #print(self.isPrecessor(words[j],words[i]))\n                if len(words[i])>len(words[j]) and self.isPrecessor(words[j],words[i]):\n                    dp[i] = max(dp[i],dp[j]+1)\n                    res = max(res,dp[i])\n        #print(dp)            \n        return res\n    \n    def isPrecessor(self,word1,word2):\n        #print('------------')\n        #print(word1)\n        #print(word2)\n        ind1 = 0\n        ind2 = 0\n        flag = 0\n        \n        while ind1<len(word1) and ind2<len(word2):\n            if word1[ind1]==word2[ind2]:\n                ind1 += 1\n                ind2 += 1\n            else: \n                if flag==1:\n                    return False\n                ind2 += 1\n                flag = 1\n                \n        return (ind1==len(word1) and ind2==len(word2)) or (ind1==len(word1) and flag==0 and (ind2+1)==len(word2))\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        sort = [[] for _ in range(max(map(len, words)))]\n        for el in words:\n            sort[len(el) - 1].append(el)\n        d = collections.defaultdict(int)\n        for row in sort:\n            for w in row:\n                for i in range(len(w)):\n                    l = w[:i] + w[i + 1:]\n                    t = d[l] + 1\n                    d[w] = max(d[w], t)\n        return max(d.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        N = len(words)\n        self.longest = [None]*N\n        max_len = 1\n        for i in range(N):\n            max_len = max(max_len, self.__findLongestAfter(words, i))\n            \n        return max_len\n                                    \n                \n    def __isPredecessor(self, w1, w2):\n        if len(w2) != len(w1)+1:\n            return False\n        \n        i=j=0\n        while i < len(w1) and j < len(w2):\n            if w1[i] == w2[j]:\n                i+=1\n            j+=1\n            \n        return (i == len(w1))\n    \n    def __findLongestAfter(self, words: List[str], i:int) -> int:\n        if self.longest[i] is not None:\n            return self.longest[i]\n        \n        self.longest[i] = 1\n        len_i = len(words[i])\n        for j in range(i+1, len(words)):\n            if len(words[j]) > len_i+1:\n                break\n                \n            if self.__isPredecessor(words[i], words[j]):\n                self.longest[i] = max(self.longest[i], self.__findLongestAfter(words, j)+1)\n                \n        return self.longest[i]", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        '''\n        [0, 2, 4, 5, 3, 1, 56, 0] -> input\n        return the length of the longest subsequence of ascending numbers\n        [1, 2, 0, 0, 0, 0, 0, 0]\n        return max(dp)\n        '''\n        \n        words.sort(key = lambda x : len(x))\n        dp  = [1] * len(words)\n        for i in range(len(words)):\n            curr = words[i]\n            for j in range(i):\n                prev = words[j]\n                if self.isPredecessor(curr, prev):\n                    dp[i] = max(dp[i], dp[j] + 1)\n        return max(dp)\n    \n    def isPredecessor(self, curr, prev):\n        if len(curr) - len(prev) != 1: return False\n        i = j = 0\n        diff = False\n        while i < len(curr) and j < len(prev):\n            if curr[i] == prev[j]:\n                i += 1\n                j += 1\n            else:\n                if diff: return False\n                diff = True\n                i += 1\n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        #backtrack/ bfs/dfs?\n        # back -> longest to smallest?\n        \n        words.sort(key = lambda x:len(x))\n        print(words)\n        n_s=len(words[0])\n        \n        dic = collections.defaultdict(lambda:0)\n        longest_chain = 1\n        \n        def search(word):\n            if len(word)==n_s:\n                dic[word] = 1\n                return 1\n            N = 1\n            for i in range(0,len(word)):\n                sub = word[0:i] + word[i+1:]\n                \n                if sub in words:\n                    n = search(sub)\n                    \n                    N =max(N,n+1)\n            dic[word]=N\n            nonlocal longest_chain\n            longest_chain = max(longest_chain,N)\n            #print(N,longest_chain,word)\n            return N\n        \n        for i in range(len(words)-1,-1,-1):\n            if dic[words[i]] in dic:\n                continue\n            word = words[i]\n            re = search(word)\n            longest_chain = max (longest_chain,re)\n        return longest_chain\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        #string : length of longest chain ends with string\n        wset= set(words)\n        \n        #return the longest chain begin with word\n        memo = {}\n        def dp(word):\n            if word in memo:\n                return memo[word]\n            #contruct all the possible successor from word\n            ans = 1\n            for i in range(len(word) + 1):\n                for j in range(26):\n                    newword = word[:i] + chr(ord('a') + j) + word[i:]\n                    if newword in wset:\n                        ans = max(ans, 1 + dp(newword))\n            memo[word] = ans\n            return ans\n        \n        ret = 0\n        for word in words:\n            if not word in memo:\n                ret = max(ret, dp(word))\n        \n        return ret", "class Solution:\n    def isSubString(self, s1, s2):\n        diff = 0;\n        l = len(s1);\n        ll = len(s2);\n        if(ll - l !=1):\n            return False\n        i = 0;\n        j = 0;\n        diff =0;\n        while(i < l and diff < 2):\n            if(s1[i] == s2[j]):\n                i += 1;\n                j += 1;\n            else:\n                j += 1;\n                diff += 1;\n        if(diff > 1):\n            return False\n        return True;\n                \n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words);\n        words = sorted(words, key = len)\n        dp = [1]*(n);\n        for i in range(n):\n            j = i-1\n            while(j >= 0 and (len(words[i]) - len(words[j]) <= 1)):\n                if(self.isSubString(words[j], words[i])):\n                    dp[i] = max(dp[i], dp[j] + 1);\n                j -= 1;\n        return max(dp)\n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x: len(x))\n        N = len(words)\n        self.longest = [None]*N\n        max_len = 1\n        for i in range(N):\n            max_len = max(max_len, self.__findLongestAfter(words, i))\n            \n        return max_len\n                                    \n                \n    def __isPredecessor(self, w1, w2):\n        if len(w2) != len(w1)+1:\n            return False\n        \n        for i in range(len(w2)):\n            if (w2[:i]+w2[i+1:]) == w1:\n                return True\n        return False\n    \n    def __findLongestAfter(self, words: List[str], i:int) -> int:\n        if self.longest[i] is not None:\n            return self.longest[i]\n        \n        max_len = 1\n        len_i = len(words[i])\n        for j in range(i+1, len(words)):\n            if len(words[j]) - len_i > 1:\n                break\n                \n            if self.__isPredecessor(words[i], words[j]):\n                max_len = max(max_len, self.__findLongestAfter(words, j)+1)\n                \n        self.longest[i] = max_len\n        return max_len", "from collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        words=sorted(words,key=lambda x:len(x))\n        \n        # hashMap=defaultdict(list)\n        # for i in range(len(words)-1,-1,-1):\n        #     for j in range(i):\n        #         if self.isPred(words[j],words[i]):\n        #             hashMap[i].append(j)\n                    \n        # dp=[1 for _ in range(len(words))]\n        # res=1\n        # for k in range(1,len(words)):\n        #     for index in hashMap[k]:\n        #         dp[k]=max(dp[k],dp[index]+1)\n        #     res=max(res,dp[k])\n        \n        dp=[1 for _ in range(len(words))]\n        res=1\n        \n        for i in range(1,len(words)):  \n            for j in range(i):\n                if self.isPred(words[j],words[i]):\n                    dp[i]=max(dp[i],dp[j]+1)\n            res=max(res,dp[i])   \n            \n        return res\n            \n \n    \n    def isPred(self,word1,word2):\n        if len(word1)+1!=len(word2):\n            return False\n        \n        p1=0\n        p2=0\n        degree=0\n        \n        while p1<len(word1) and p2<len(word2):\n            if word1[p1]==word2[p2]:\n                p1+=1\n                p2+=1\n                continue\n            else:\n                degree+=1\n                p2+=1\n               \n        return degree<2\n\n                \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        di = defaultdict(list)\n        for w in words:\n            di[len(w)].append(w)\n        L, U = min(di.keys()), max(di.keys())\n        dp = [1] * len(di[L])\n        ans = 1\n        \n        def ispred(w1, w2):\n            skip = False\n            for i in range(len(w1)):\n                while w1[i] != w2[i + skip]:\n                    if skip:\n                        return False\n                    skip = True\n            return True\n        \n        for l in range(L+1, U+1):\n            old = dp\n            dp = [1] * len(di[l])\n            for j, w2 in enumerate(di[l]):\n                tmp = [old[i] for i, w1 in enumerate(di[l-1]) if ispred(w1, w2)]\n                if tmp: dp[j] = max(tmp) + 1\n            ans = max(ans, max(dp))\n            \n        return ans\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n= len(words)\n        def extraChar(s1, s2):\n            l1, l2 = sorted(s1), sorted(s2)\n            \n            diff =0\n            i,j = 0,0\n            if len(s1) == len(s2) + 1: \n                while i<len(s1) and j<len(s2):\n                    if l1[i] != l2[j]: \n                        i+=1\n                        diff+=1\n                     \n                    else:\n                        i+=1\n                        j+=1\n                    \n                if i==len(s1) and j== len(s2): return diff==1\n                elif i==len(s1)-1: return True\n                \n            return False\n                    \n        \n        mem = {}\n        words.sort(key = lambda x: len(x))\n        \n        \n        def dp(i):\n            if i>=n: return 0\n            if i in mem: return mem[i]\n            mem[i] = 1\n            for j in range(i+1, n):\n                \n                if len(words[j]) == len(words[i])+1 and extraChar(words[j], words[i]):\n                    #print('words[j]: ', words[j], ' words[j]: ', words[i])\n                    mem[i] =  max(mem[i], dp(j)+1)\n                    \n                elif len(words[j]) > len(words[i])+1: break\n        \n            return mem[i]\n        \n        \n        return max([dp(i) for i in range(n)])", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        mark = {}\n        queue = []\n        for index, word in enumerate(words):\n            mark[word] = collections.Counter(word)\n            queue.append([[word],index, len(word)])\n        ans = 0\n        while queue:\n            s, index, l = queue.pop(0)\n            flag = True\n            for i in range(index+1, len(words)):\n                if len(words[i]) > l+1:\n                    break\n                if len(words[i]) == l+1:\n                    add = True\n                    sum1 = 0\n                    sum2 = 0\n                    for key in list(mark[s[-1]].keys()):\n                        if key not in mark[words[i]]:\n                            add = False\n                            break\n                        sum1 += mark[s[-1]][key]\n                        sum2 += mark[words[i]][key]\n                    if add and (sum1 == sum2 or sum2-sum1 == 1):\n                        queue.append([s+[words[i]], i, l+1])\n                        flag = False\n            if flag:\n                ans = max(ans, len(s))       \n        return ans\n                        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        '''\n        [0, 2, 4, 5, 3, 1, 56, 0] -> input\n        return the length of the longest subsequence of ascending numbers\n        [1, 2, 0, 0, 0, 0, 0, 0]\n        return max(dp)\n        '''\n        \n        words.sort(key = lambda x : len(x))\n        dp  = [1] * len(words)\n        ans = 0\n        for i in range(len(words)):\n            curr = words[i]\n            for j in range(i):\n                prev = words[j]\n                if self.isPredecessor(curr, prev):\n                    dp[i] = max(dp[i], dp[j] + 1)\n            ans = max(ans, dp[i])\n        return ans\n    \n    def isPredecessor(self, curr, prev):\n        if len(curr) - len(prev) != 1: return False\n        i = j = 0\n        diff = False\n        while i < len(curr) and j < len(prev):\n            if curr[i] == prev[j]:\n                i += 1\n                j += 1\n            else:\n                if diff: return False\n                diff = True\n                i += 1\n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words: return 0\n        words.sort(key=lambda x: len(x))\n        dp = [1] * len(words)\n        for i in range(len(words)):\n            curr = words[i]\n            for j in range(i):\n                prev = words[j]\n                if (self.checkPredecessor(curr, prev)):\n                    dp[i] = max(dp[i], dp[j] + 1)\n        return max(dp)\n                    \n                    \n    def checkPredecessor(self, curr, prev):\n        if len(curr) - len(prev) != 1: return False\n        i = j = 0\n        diff = False\n        while i < len(curr) and j < len(prev):\n            if curr[i] == prev[j]:\n                i += 1\n                j += 1\n            else:\n                if diff: return False\n                diff = True\n                i += 1\n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        hashmap = collections.defaultdict(list)\n        for index, word in enumerate(words):\n            hashmap[len(word)].append(index)\n        n = len(words)\n        graph = [[False for _ in range(n)] for _ in range(n)]\n        \n        def predecessor(a, b):\n            mistake = 0\n            for i in range(len(a)):\n                if a[i] != b[i + mistake]:\n                    mistake += 1\n                    if mistake > 1 or a[i] != b[i + mistake]:\n                        return False\n            return True\n        \n        for index, word in enumerate(words):\n            for candidate in hashmap[len(word)+1]:\n                if predecessor(word, words[candidate]):\n                    graph[index][candidate] = True\n        dp = [-1 for _ in range(n)]\n        \n        def dfs(i):\n            if dp[i] != -1:\n                return dp[i]\n            answer = 0\n            for j in range(n):\n                if graph[i][j]:\n                    answer = max(answer, dfs(j))\n            dp[i] = answer + 1\n            #print(f'i = {i}, dp[i]={dp[i]}')\n            return answer + 1\n        \n        answer = 0\n        for i in range(n):\n            answer = max(answer, dfs(i))\n        return answer", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_edit(a, b):\n            if abs(len(a) - len(b)) > 1:\n                return False\n            if len(a) == len(b):\n                return False\n\n            for i in range(min(len(a), len(b))):\n                if a[i] != b[i]:\n                    return a == b[:i] + b[i + 1:] or b == a[:i] + a[i + 1:]\n            return True\n\n        words.sort(key=lambda x: len(x))\n        n = len(words)\n        memo = [1 for _ in range(n)]\n        ans = 1\n        for i in range(n - 1, -1, -1):\n            max_ = 0\n            for j in range(i + 1, n):\n                if is_edit(words[i], words[j]):\n                    max_ = max(max_, memo[j])\n            memo[i] = 1 + max_\n            ans = max(memo[i], ans)\n        return ans\n", "from functools import lru_cache\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        #string : length of longest chain ends with string\n        wset= set(words)\n        \n        #return the longest chain begin with word\n        memo = {}\n        def dp(word):\n            if word in memo:\n                return memo[word]\n            #contruct all the possible successor from word\n            ans = 1\n            for i in range(len(word) + 1):\n                for j in range(26):\n                    newword = word[:i] + chr(ord('a') + j) + word[i:]\n                    if newword in wset:\n                        ans = max(ans, 1 + dp(newword))\n            memo[word] = ans\n            return ans\n        \n        ret = 0\n        for word in words:\n            if not word in memo:\n                ret = max(ret, dp(word))\n        \n        return ret", "from collections import Counter\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = [1]\n        res = 0\n        words = sorted(words, key=lambda x:len(x))\n        for i in range(1,len(words)):\n            j = i-1\n            val = 1\n            while(j >= 0):\n                if len(words[j]) != len(words[i]) - 1:\n                    j -= 1\n                    continue\n                counter_j, counter_i = Counter(words[j]), Counter(words[i])\n                used = False\n                \n                for key, value_j in counter_j.items():\n                    value_i = counter_i.get(key)\n                    if not value_i or value_i > value_j+1 or value_i < value_j:\n                        break\n                    \n                    if value_i == value_j+1 and used:\n                        break\n                    \n                    if value_i == value_j+1 and not used:\n                        used = True    \n                else:\n                    val = max(val, dp[j]+1)\n                j-=1\n            dp.append(val)\n            res = max(val, res)\n        \n        print(dp)\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n                # contruct a graph linking predecessor\n        def isPred(word1, word2):\n            # len(word2) > len(word1)\n            for i in range(len(word2)):\n                if word2[0:i] + word2[i+1:] == word1:\n                    return True\n            return False\n        graph = {}\n        for i in range(len(words) - 1):\n            for j in range(i + 1, len(words)):\n                w1, w2 = words[i], words[j]\n                if len(w2) - len(w1) == 1 and isPred(w1, w2):\n                    if w1 in graph:\n                        graph[w1].append(w2)\n                    else:\n                        graph[w1] = [w2]\n                elif len(w2) - len(w1) == -1 and isPred(w2, w1):\n                    if w2 in graph:\n                        graph[w2].append(w1)\n                    else:\n                        graph[w2] = [w1]\n        self.res = 0\n        def dfs(word, lev):\n            # no need to mark visited here as len goes up\n            self.res = max(self.res, lev)\n            if word not in graph:\n                return\n            for i in graph[word]:\n                dfs(i, lev+1)\n        for i_word in words:\n            dfs(i_word, 1)\n        return self.res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        st = set(words)\n\n        def ls(word):\n            res = 1\n            for j in range(len(word)):\n                substr = word[:j] + word[(j+1):]\n                if substr not in st:\n                    continue\n                res = 1 + ls(substr)\n            return res\n           \n        res = 1\n        for word in words:\n            res = max(res, ls(word))\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        N = len(words)\n        dp = [1]*N\n        words.sort(key=len)\n        print(words)\n        if N == 1:\n            return 1\n        def check(word1, word2):\n            if len(word2) - len(word1) != 1:\n                return False\n            n = len(word1)\n            for i in range(n):\n                # print(word2[:i] + word2[i+1:])\n                if word2[:i] + word2[i+1:] == word1:\n                    return True\n                if word2[:-1] == word1:\n                    return True\n            return False\n                \n        for i in range(N):\n            for j in range(i):\n                if check(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j]+1)\n                    \n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def f(x, y):\n            if len(x) != len(y) - 1:\n                return False\n            p = len(x)\n            for i in range(len(x)):\n                if x[i] != y[i]:\n                    p = i\n                    break\n            \n            for i in range(p, len(x)):\n                if x[i] != y[i + 1]:\n                    return False\n            return True\n\n        words.sort(key=lambda x:len(x))\n        \n        a = []\n        for _ in range(len(words)):\n            a.append([False] * len(words))\n            \n        \n        for i in range(len(words)):\n            for j in range(i + 1, len(words)):\n                a[i][j] = f(words[i], words[j])\n                \n        # print(a)\n                \n        dp = [1] * len(words)\n        for i in range(1, len(words)):\n            for j in range(i):\n                if a[j][i]:\n                    dp[i] = max(dp[i], dp[j] + 1)\n        return max(dp)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        word_dict= {}\n        words= [(len(w), w) for w in words]\n        words = sorted(words)\n\n        for _,w in words:\n            word_dict[w] = 1\n            \n        state_t = set() #word and chainlen\n        \n        max_chain = 1\n        for _,word in words:\n\n            chain_len = word_dict[word]\n            max_chain = max(max_chain, chain_len)\n            for i in range(len(word)+1):\n                for c in range(97,123):\n                    \n                    new_word = word[:i] + chr(c)  + word[i:]\n                    \n                    \n\n                    if word_dict.get(new_word, False) and new_word not in state_t:\n                        \n                        state_t.add(new_word)\n                        word_dict[new_word] = chain_len+1\n                        \n        return max_chain\n        \n        \n        \n        \n        \n            \n        \n            \n            \n", "from collections import defaultdict\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        length = defaultdict(list)\n        \n        for s in words:\n            length[len(s)].append(s)\n        \n        record = sorted(list(length.items()), reverse=True)\n        result = defaultdict(int)\n        max_length = 1\n        for item in record:\n            for word in item[1]:\n                if result[word] == 0:\n                    result[word] += 1\n                for i in range(len(word)):\n                    new_string = word[0:i]+word[i+1:] \n                    if new_string in words:\n                        result[new_string] = max(result[new_string], result[word]+1)\n                        max_length = max(max_length, result[new_string])\n        \n        return max_length\n                        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dic = defaultdict(list)\n        words.sort(key = len, reverse = True)\n        for w in words:\n            for i in range(len(w)):\n                if w[:i] + w[i+1:] in words:\n                    dic[w].append(w[:i] + w[i+1:])\n        def bt(x):\n            return [[x]] if x not in dic else [[x] + rest for y in dic[x] for rest in bt(y)]\n        ct = 1\n        for word in words:\n            ct = max(ct, len(max(bt(word), key = len)))\n        return ct\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        dp = [1 for _ in words]\n        largest = 1\n        words.sort(key=lambda s:len(s))\n        print(words)\n        def predecessor(big_word, small_word):\n            b = 0\n            s = 0\n            mismatch = False\n            if len(small_word) + 1 != len(big_word):\n                return False\n            while b < len(big_word) and s < len(small_word):\n                if big_word[b] != small_word[s] and not mismatch:\n                    mismatch = True\n                    b += 1\n                    continue\n                elif big_word[b] == small_word[s]:\n                    s += 1\n                    b += 1\n                    continue\n                else:\n                    return False\n            return True\n\n        left = 0\n        right = 0\n        while right < len(words):\n            for k in range(left, right):\n                if len(words[k]) == words[right]:\n                    left = right\n                    break\n                if predecessor(words[right], words[k]):\n                    dp[right] = max(dp[right], dp[k] + 1)\n                    largest = max(dp[right], largest)\n            right += 1\n        return largest", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        if not words:return 0\n        \n        words.sort(key=lambda x:len(x))\n        \n        counter=[collections.Counter(word) for word in words]\n        \n        dp=[1]*len(words)\n        maxlen=0\n        for i in range(len(dp)):\n            for j in range(i):\n                if len(words[i])-len(words[j])==1 and len((counter[i]-counter[j]))==1:\n                    dp[i]=max(dp[i],1+dp[j])\n                    \n            maxlen=max(maxlen,dp[i])\n            \n            \n        return maxlen\n                \n", "class Solution:\n    def __init__(self):\n        self.cache = collections.defaultdict(int)\n    \n    def longestEndWith(self, word, words):\n        if word in self.cache:\n            return self.cache[word]\n        if len(word) == 1:\n            self.cache[word] = 1\n            return 1\n        else:\n            for i in range(len(word)):\n                s = word[:i] + word[i+1:]\n                if s in words:\n                    self.cache[word] = max(self.cache[word], self.longestEndWith(s, words))\n            self.cache[word] += 1\n            return self.cache[word]\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        ans = 0\n        \n        for word in words:\n            ans = max(ans, self.longestEndWith(word, words))\n        \n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        from collections import defaultdict, deque\n        hash_map = defaultdict(list)\n\n        max_len = 0\n        q = deque()\n        for char in words:\n            if len(char) >1:\n                neighbors = [char[:i] + char[i+1:] for i in range(len(char))]\n                for n in neighbors:\n                    hash_map[n].append(char)\n            hash_map[char].append(char)\n\n        for c in words:\n            visited = {}\n            q.append((c, 1))\n            while q:\n                char, count = q.pop()\n                if char not in visited and char in hash_map:\n                    max_len = max(max_len, count)\n                    for n in hash_map[char]:\n                        q.append((n, count + 1))\n\n                visited[char] = 1\n        return max_len\n                    \n\n", "class Solution:\n    def __init__(self):\n        self.cache = collections.defaultdict(int)\n    \n    def longestEndWith(self, word, words):\n        if word in self.cache:\n            return self.cache[word]\n        if len(word) == 1:\n            self.cache[word] = 1\n            return 1\n        else:\n            for i in range(len(word)):\n                s = word[:i] + word[i+1:]\n                if s in words:\n                    self.cache[word] = max(self.cache[word], self.longestEndWith(s, words))\n            self.cache[word] += 1\n            return self.cache[word]\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x: len(x)) \n        ans = 0\n        \n        for word in words[::-1]:\n            if word not in self.cache:\n                ans = max(ans, self.longestEndWith(word, words))\n        \n        return ans", "class Solution:\n    def __init__(self):\n        self.cache = collections.defaultdict(int)\n    \n    def longestEndWith(self, word, words):\n        if word in self.cache:\n            return self.cache[word]\n        if len(word) == 1:\n            self.cache[word] = 1\n            return 1\n        else:\n            for i in range(len(word)):\n                s = word[:i] + word[i+1:]\n                if s in words:\n                    self.cache[word] = max(self.cache[word], self.longestEndWith(s, words))\n            self.cache[word] += 1\n            return self.cache[word]\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda x: len(x)) \n        ans = 0\n        \n        for word in words[::-1]:\n            if word not in self.cache:\n                ans = max(ans, self.longestEndWith(word, words))\n                if ans == len(words):\n                    break\n        \n        return ans", "from collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        ends_at = defaultdict(int)\n        words = sorted(words, key = lambda x: len(x))\n        ans = 0\n        for w in words:\n            ends_at[w] = 1\n            for i, ch in enumerate(w):\n                prev = w[:i] + w[i+1:]\n                if prev in words:\n                    ends_at[w] = max(ends_at[w], ends_at[prev] + 1)\n            ans = max(ans, ends_at[w])\n        return ans\n", "class Solution:\n    def __init__(self):\n        self.cache = collections.defaultdict(int)\n    \n    def longestEndWith(self, word, words):\n        if word in self.cache:\n            return self.cache[word]\n        if len(word) == 1:\n            self.cache[word] = 1\n            return 1\n        else:\n            for i in range(len(word)):\n                s = word[:i] + word[i+1:]\n                if s in words:\n                    self.cache[word] = max(self.cache[word], self.longestEndWith(s, words))\n            self.cache[word] += 1\n            return self.cache[word]\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        ans = 0\n        \n        for word in words[::-1]:\n            if word not in self.cache:\n                ans = max(ans, self.longestEndWith(word, words))\n        \n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        '''\n        DFS with memo\n        '''\n        # words = set(words)\n        dp = {}\n        def chainEndingAt(word):\n            if word not in words:\n                return 0\n            if word not in dp:\n                chain_len = 1\n                for i in range(len(word)):\n                    pred = word[:i] + word[i+1:]\n                    chain_len = max(chain_len, chainEndingAt(pred) + 1)\n                dp[word] = chain_len\n            return dp[word]\n        \n        ans = 0\n        for word in words:\n            ans = max(ans, chainEndingAt(word))\n        return ans\n        \n        '''\n        DP\n        dp function:\n        chain[word2] = max(chain[word1]+1 for all word1 if word1 is predecessor of word2)\n        '''\n        # dp = {}\n        # for w in sorted(words, key=len):\n        #     dp[w] = 1\n        #     for i in range(len(w)):\n        #         dp[w] = max(dp[w], dp.get(w[:i] + w[i+1:],0) + 1)\n        # return max(dp.values())\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = sorted(words, key = len)\n        n = len(words)\n        def match(l, r):\n            a = words[l]\n            b = words[r]\n            if (len(a) + 1 != len(b)):\n                return False\n            i,j = 0,0\n            while i < len(a) and j < len(b):\n                if (a[i] == b[j]):\n                    i += 1\n                j += 1\n            return i == len(a)\n        \n        dp = [0 for _ in range(n)]\n        for i in range(n-2, -1, -1):\n            for j in range(i+1, n):\n                if (len(words[j]) > len(words[i])+1):\n                    break\n                if match(i, j):\n                    dp[i] = max(dp[i], 1 + dp[j])\n        return 1+max(dp)", "class Solution:\n    def __init__(self):\n        self.cache = collections.defaultdict(int)\n    \n    def longestEndWith(self, word, words):\n        if word in self.cache:\n            return self.cache[word]\n        if len(word) == 1:\n            self.cache[word] = 1\n            return 1\n        else:\n            for i in range(len(word)):\n                s = word[:i] + word[i+1:]\n                if s in words:\n                    self.cache[word] = max(self.cache[word], self.longestEndWith(s, words))\n            self.cache[word] += 1\n            return self.cache[word]\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        ans = 0\n        \n        for word in words:\n            if word not in self.cache:\n                ans = max(ans, self.longestEndWith(word, words))\n        \n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        by_length = collections.defaultdict(set)\n        for word in words:\n            by_length[len(word)].add(word)\n\n        longest = 1\n        seen = {*()} # set()\n        mx = len(by_length)\n\n        # in descending order\n        for length in sorted(by_length, reverse=True):\n            for word in by_length[length]:\n                if longest == mx:\n                    break\n                if word in seen:\n                    continue\n                stk = [(word, length, 1)]\n                while stk:\n                    word, k, n = stk.pop()\n                    seen.add(word)\n                    if n > longest:\n                        longest = n\n                    for i in range(k):\n                        pre = word[:i] + word[i+1:]\n                        if pre not in seen and pre in by_length[k-1]:\n                            stk.append((pre, k-1, n+1))\n\n        return longest   ", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        dictByLen = collections.defaultdict(list)\n        wordCounter = {}\n        \n        for i,w in enumerate(words):\n            dictByLen[len(w)].append(w)\n            wordCounter[w] = collections.Counter(w)\n            \n        def isOneDiff(s1, s2):\n            diff = 0\n            j = 0\n            for c in s2:\n                if c != s1[j]:\n                    if diff == 1:\n                        return False\n                    diff += 1\n                else:\n                    j += 1\n                    if j == len(s1):\n                        return True\n            return True\n                    \n        sortedLens = sorted(dictByLen.keys())  \n        longestLen = 1\n        \n        \n        prevLen = -1\n        \n        for l in sortedLens:\n            if prevLen == -1 or l != (prevLen + 1):\n                prevArr = [(s,1) for s in dictByLen[l]]\n            else:\n                newArr = []\n                \n                for s2 in dictByLen[l]:\n                    diff = 1\n                    for s1, lsf in prevArr:\n                        if isOneDiff(s1, s2):\n                            diff = max(diff, lsf + 1)\n                            \n                    newArr.append((s2, diff))\n                    longestLen = max(diff, longestLen)\n                prevArr = newArr\n            prevLen = l\n        \n        return longestLen\n                \n            \n        \n\n                \n                                \n                        \n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = lambda w: len(w))\n        graph = {}\n        indegree = {}\n        for w in words:\n            graph[w] = []\n            indegree[w] = 0\n        \n        def is_pre(wd_sml, wd_lrg):\n            for idx in range(len(wd_lrg)):\n                if wd_lrg[:idx] + wd_lrg[idx+1:] == wd_sml:\n                    return True\n            return False\n        \n        for idx in range(1, len(words)):\n            for idx2 in range(idx):\n                if len(words[idx]) != len(words[idx2])+1:\n                    continue\n                if is_pre(words[idx2], words[idx]):\n                    graph[words[idx2]].append(words[idx])\n                    indegree[words[idx]] += 1\n        \n        memo = {}\n        from collections import deque\n        def dfs(wd):\n            if wd in memo:\n                return memo[wd]\n            res = 1\n            for nei in graph[wd]:\n                res = max(res, 1+dfs(nei))\n            memo[wd] = res\n            return memo[wd]\n            \n        \n        st_arr = [w for w,indeg in list(indegree.items()) if not indeg]\n        \n        max_len = 0\n        \n        for elt in st_arr:\n            res_len = dfs(elt)\n            max_len = max(res_len, max_len)\n        \n        return max_len\n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def edit_dist(w1, w2):\n            n = len(w1)\n            m = len(w2)\n            if n + 1 != m:\n                return False\n            mismatch = 0\n            i = 0\n            j = 0\n            while i < n and j < m:\n                if w1[i] != w2[j]:\n                    mismatch += 1\n                    j += 1\n                else:\n                    i += 1\n                    j += 1\n            return mismatch <= 1\n        \n        def recurse(word, length):\n            nonlocal max_l\n            max_l = max(max_l, length)\n            n = len(word) + 1\n            if n in dic:\n                for next_word in dic[n]:\n                    if edit_dist(word, next_word):\n                        recurse(next_word, length+1)\n                        \n        \n        dic = collections.defaultdict(list)\n        \n        for word in words:\n            dic[len(word)].append(word)\n        max_l = 0\n        \n        for word in words:\n            recurse(word, 1)\n        return max_l\n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        word_graph = {}\n        for word in words:\n            for second_word in words:\n                if len(second_word) == len(word) + 1:\n                    is_predecessor = True\n                    second_word_counter = Counter(second_word)\n                    first_word_counter = Counter(word)\n                    for key, value in list(first_word_counter.items()):\n                        if second_word_counter[key] < value:\n                            is_predecessor = False\n                            break\n                    if is_predecessor:\n                        if word in word_graph:\n                            word_graph[word].append(second_word)\n                        else:\n                            word_graph[word] = [second_word]\n        max_level = 1\n        for key, value in list(word_graph.items()):\n            queue = deque()\n            queue.append((key, 1))\n            visted = set()\n            while queue:\n                curr, level = queue.popleft()\n                if level > max_level:\n                    max_level = level\n                if curr in word_graph:\n                    for next_word in word_graph[curr]:\n                        queue.append((next_word, level + 1))\n\n        return max_level\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        explored = set()\n        stack = [(word, 1) for word in sorted(words, key = len, reverse = True)]\n        words = set(words)\n        best = 1\n        while stack:\n            word, chain_length = stack.pop()\n            best = max(best, chain_length)\n            for candidate_word in [word[:i] + c + word[i:] for c in 'abcdefghijklmnopqrstuvwxyz' for i in range(len(word) + 1)]:\n                if candidate_word in words and candidate_word not in explored:\n                    stack.append((candidate_word, chain_length + 1))\n                    explored.add(candidate_word)\n        return best\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def dfs(str):\n            dep = 1\n            for longer_str in words:\n                if len(longer_str) == len(str)+1:\n                    for i in range(len(str)+1):\n                        new_str = longer_str[:i] + longer_str[i+1:] \n                        if new_str == str:\n                            dep = max(dep,dfs(longer_str)+1)\n                            seen.append(longer_str)\n            return dep\n        \n        seen = []\n        depth = []\n        words = sorted(words, key=len)\n        for str in words:\n            if str not in seen:\n                depth.append(dfs(str))\n                \n        return max(depth)", "from collections import Counter\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        def helper(s1, s2):\n            if len(s1) != len(s2) - 1:\n                return False\n            s1 = Counter(s1)\n            s2 = Counter(s2)\n            diff = 0\n            for j in s2:\n                if j not in s1:\n                    diff += 1\n                elif s2[j] != s1[j]:\n                    diff += 1\n                if diff >= 2:\n                    return False\n            return diff == 1\n    \n        dps = [1 for _ in words]\n        for j in range(len(words)):\n            _max = 1\n            for i in range(j):\n                if helper(words[i], words[j]):\n                    _max = max(_max, dps[i] + 1)\n            dps[j] = _max\n        return max(dps)\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n\n        # general: create arrays of strings of each length, \n        \n        # minimum is one, max is length of the longest word \n        \n        # sort and split by length\n        \n        # BFS by length and at each \n        \n        words.sort(key=lambda x: len(x))\n\n        wordLevels = {}\n        \n        for word in words:\n            if len(word) in wordLevels:\n                wordLevels[len(word)].append(word)\n            else:\n                wordLevels[len(word)] = [word]\n                \n        result = 0\n        words.reverse()\n        for word in words:\n            result = max(result, self.getChain(word, wordLevels, 1))\n            \n        return result\n    \n    \n    \n    def getChain(self, word, wordLevels, length):\n        # dfs here\n        \n        level = len(word)\n        for i in range(len(word)):\n            if level-1 in wordLevels:\n                if word[:i]+word[i+1:] in wordLevels[level-1]:\n                    return self.getChain(word[:i]+word[i+1:], wordLevels, length+1)\n \n        return length\n        \n        \n", "class Solution:\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        x=lambda a:len(a)\n        words.sort(key=x)\n        print(words)\n        chain_len=[None]*len(words)\n        chain_len[0]=1\n        \n        \n        \n        \n        for i in range(1,len(words)):\n            temp=words[i]\n            chain_len[i]=1\n            for j in range(len(temp)):\n                temp2=temp[:j]+temp[j+1:]\n                if (temp2 not in words) :\n                    continue\n                for k in range(i-1,-1,-1):\n                    if (len(words[k])<len(words[i])-1):\n                        break        \n                    else:\n                          if (len(words[k])==len(words[i])-1):\n                                  if words[k]==temp2:\n                                        chain_len[i]=max(chain_len[i],chain_len[k]+1)\n                                        break\n                        \n        return max(chain_len)", "from collections import deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        # return self.run_graph_solution(words)\n        return self.run_dp_solution(words)\n    \n    def run_dp_solution(self, words):\n        \n        mem = {'': 0}\n        \n        def inner(w):\n            if w in mem or w not in words:\n                return\n            \n            max_per_w = 1\n            for j in range(len(w)):\n                cur = w[:j] + w[j+1:]\n                if cur in mem:\n                    val = mem[cur] + 1\n                else:\n                    inner(cur)\n                    if cur not in mem:\n                        val = 1\n                    else:\n                        val = mem[cur] + 1\n                if val > max_per_w:\n                    max_per_w = val\n            mem[w] = max_per_w\n            return\n        \n        for w in words:\n            inner(w)\n            \n        return max(mem.values())\n        \n    def run_graph_solution(self, words):\n        graph = {word: [] for word in words}\n        lengths = {k: [] for k in range(1, 17)}\n        into = {}\n        min_len = 17\n        max_len = 1\n        for word in words:\n            lengths[len(word)].append(word)\n            min_len = min(len(word), min_len)\n            max_len = max(len(word), max_len)\n                    \n        for k in range(min_len, max_len):\n            for word1 in lengths[k]:\n                for word2 in lengths[k + 1]:\n                    for i in range(len(word2)):\n                        if word2[:i] + word2[i+1:] == word1:\n                            graph[word1].append(word2)\n                            into[word2] = True     \n                            \n        sources = [word for word in words if word not in into]\n        max_len = 0\n        for s in sources:\n            max_len = max(max_len, self.run_bfs(s, graph))\n        return max_len\n                \n    def run_bfs(self, s, graph):\n        queue = deque(maxlen=len(list(graph.keys())))\n        queue.appendleft((s, 1))\n        summary = []\n        \n        while len(queue) > 0:\n            current_node, cur_len = queue.pop()\n            for word in graph[current_node]:\n                queue.appendleft((word, cur_len + 1))\n            summary.append(cur_len)\n        \n        return summary[-1]\n    \n    \n            \n            \n        \n        \n        \n        \n        \n", "from collections import deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        # return self.run_graph_solution(words)\n        return self.run_dp_solution(words)\n    \n    def run_dp_solution(self, words):\n        \n        mem = {'': 0}\n        \n        def inner(w):\n            if w in mem or w not in words:\n                return\n            \n            max_per_w = 1\n            for j in range(len(w)):\n                cur = w[:j] + w[j+1:]\n                if cur in mem:\n                    val = mem[cur] + 1\n                elif cur not in words:\n                    val = 1\n                else:\n                    inner(cur)\n                    val = mem[cur] + 1\n                if val > max_per_w:\n                    max_per_w = val\n            mem[w] = max_per_w\n            return\n        \n        for w in words:\n            inner(w)\n            \n        return max(mem.values())\n        \n    def run_graph_solution(self, words):\n        graph = {word: [] for word in words}\n        lengths = {k: [] for k in range(1, 17)}\n        into = {}\n        min_len = 17\n        max_len = 1\n        for word in words:\n            lengths[len(word)].append(word)\n            min_len = min(len(word), min_len)\n            max_len = max(len(word), max_len)\n                    \n        for k in range(min_len, max_len):\n            for word1 in lengths[k]:\n                for word2 in lengths[k + 1]:\n                    for i in range(len(word2)):\n                        if word2[:i] + word2[i+1:] == word1:\n                            graph[word1].append(word2)\n                            into[word2] = True     \n                            \n        sources = [word for word in words if word not in into]\n        max_len = 0\n        for s in sources:\n            max_len = max(max_len, self.run_bfs(s, graph))\n        return max_len\n                \n    def run_bfs(self, s, graph):\n        queue = deque(maxlen=len(list(graph.keys())))\n        queue.appendleft((s, 1))\n        summary = []\n        \n        while len(queue) > 0:\n            current_node, cur_len = queue.pop()\n            for word in graph[current_node]:\n                queue.appendleft((word, cur_len + 1))\n            summary.append(cur_len)\n        \n        return summary[-1]\n    \n    \n            \n            \n        \n        \n        \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        # pred  = [1  , 1 , 1  , 1   , 1+ba, 1+bda]\n        # d = {}\n        # d[length] = [list of words]\n        # d[1] = [\\\"a\\\", \\\"b\\\"] , ...\n        # 26*C\n        \n        \n        # words = [\\\"a\\\",\\\"b\\\",\\\"ba\\\",\\\"bca\\\",\\\"bda\\\",\\\"bdca\\\"]\n        # pred  = [1  , 1 , 2  , 3   , 3   , 4    ]\n        # solution 1:\n        # sort words by their length, O(N log N)\n        # O(N^2) time to update each pred based on its last values,\n        # find the maximum value in pred.\n        # O(N^2*C^2) time, O(N) space,\n        \n        words = sorted(words, key = lambda x:len(x))\n        \n        #build an array of length words with default 1,\n        pred  = [1]*len(words)\n        \n        def diff1(w1, w2):\n            for i in range(len(w2)):\n                if w2[:i]+w2[i+1:] == w1:\n                    return True\n            return False\n        def diff2(w1, w2):\n            i = 0\n            while i<len(w1) and w1[i]==w2[i]:\n                i+=1\n            j=len(w1)-1\n            while j>=i and w1[j]==w2[j+1]:\n                j -= 1\n            if j==i-1:\n                return True\n            return False\n        \n        # compare each word with words with length-1, \n        for i in range(len(words)):\n            j = i-1\n            while j>=0 and abs(len(words[j]) - len(words[i])) <2:\n                if len(words[j])==len(words[i])-1 and diff2(words[j], words[i]):\n                    pred[i] = max(pred[i], pred[j]+1)\n                j -= 1\n        \n        return max(pred)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        \n        words.sort(key = len)\n        print(words)\n        def stringmatch(s1,s2):\n            onemismatchallowed = True\n            \n            if(len(s1)>len(s2)):\n                s2,s1 = s1,s2\n                \n            # print(\\\"s1\\\",\\\"s2\\\",s1,s2)\n    \n            if(len(s1)+1!=len(s2)):\n                return False\n            i,j=0,0\n            while(i<len(s1)):\n                if(s1[i]!=s2[j]):\n                    if(onemismatchallowed==True):\n                        onemismatchallowed = False\n                    else:\n                        return False\n                    j+=1\n                else:\n                    i+=1\n                    j+=1\n                    \n            return True\n        \n        dp = [1 for _ in range(len(words))]\n        \n        # dp[0] = 1\n        ans = 1\n        for i in range(1,len(words)):\n            j = i-1\n            while(j>=0 and len(words[j])+1>=len(words[i])):\n                \n                val = stringmatch(words[j],words[i])\n                if(val):\n                    print(words[j],words[i])\n                    print(dp[i])\n                    dp[i] = max(dp[j]+1,dp[i])\n                    ans = max(dp[i],ans)\n                j-=1\n        print(dp)\n                    \n        return ans", "class Solution:\n    def __init__(self):\n        self.results = []\n        self.explored = dict()\n        \n    def traverse(self, string, listt, buffer):\n        flag = True\n        for i in range(len(string)):\n            if string[:i]+string[i+1:] in listt:\n                flag = False\n                self.traverse(string[:i]+string[i+1:], listt, buffer+[string[:i]+string[i+1:]])\n        if flag:\n            self.results.append(buffer)\n            for item in buffer:\n                self.explored[item] = True\n        return\n        \n        \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len, reverse=True)\n        for word in words:\n            if word not in self.explored:\n                self.traverse(word, words, [word])\n        return len(max(self.results, key=len))", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(w1, w2):\n            if(len(w1) + 1 != len(w2)):\n                return False\n            \n            skip = 0\n            for i in range(len(w2)):\n                j = i - skip\n                if(j == len(w1)):\n                    break\n                if(w1[j] != w2[i]):\n                    skip += 1\n                    if(skip >= 2):\n                        return False\n            \n            return True\n        \n        words.sort(key=len, reverse=True)\n        len_words = len(words)\n        combos = [0] * len_words\n        \n        for i in range(len_words):\n            for j in range(0, i):\n                if(combos[i] < combos[j] + 1 and is_predecessor(words[i], words[j])):\n                    # print(words[i] + ', ' + words[j])\n                    combos[i] = combos[j] + 1\n                    \n        # for i in range(len_words):\n        #     print(combos[i], end=', ')\n        #     print(words[i])\n        \n        \n        return max(combos) + 1\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(str1, str2):\n            if len(str1) + 1 != len(str2):\n                return False\n            else:\n                for i in range(len(str2)):\n                    if str1 == str2[:i] + str2[i+1:]:\n                        return True\n                return False\n        l = len(words)\n        words.sort(key=len)\n        mat = [[0 for j in range(l)] for i in range(l)]\n        mat_max = 0\n        for i in range(l):\n            for j in range(i, l):\n                if is_predecessor(words[i], words[j]):\n                    mat[i][j] = mat[i][i] + 1\n                    mat[j][j] = max(mat[j][j], mat[i][j])\n                    mat_max = max(mat_max, mat[i][j])\n        return mat_max + 1", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        st = set(words)\n\n        def ls(word):\n            res = 1\n            for j in range(len(word)):\n                substr = word[:j] + word[(j+1):]\n                if substr not in st:\n                    continue\n                res = max(res, 1 + ls(substr))\n            return res\n           \n        res = 1\n        for word in words:\n            res = max(res, ls(word))\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        words_len = len(words)\n        \n        def predecessor(word, candidate):\n            if len(word) != len(candidate)+1:\n                return False\n            j = 0\n            for i, c in enumerate(word):\n                if i > j + 1 or j == len(candidate):\n                    break\n                if c == candidate[j]:\n                    j += 1\n            return j == len(candidate)\n        \n        \n        dp = [1] * words_len\n        for i in range(words_len):\n            # cur_possibles = makePossibles(words[i])\n            curLen = len(words[i])\n            for j in range(i - 1, -1, -1):\n                if len(words[j]) < curLen-1:\n                    break\n                if predecessor(words[i], words[j]):\n                    dp[i] = max(dp[i], 1 + dp[j])\n                \n            \n        \n        return max(dp)\n        \n        # makePossibles(words[2])\n        # getAdjacents(words[2], 2)\n        # print(words)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def pred(origin,dest):\n            if len(dest) - len(origin) != 1:\n                return False\n            misWord = False\n            oIndex = 0\n            for index in range(len(dest)):\n                if oIndex == len(origin):\n                    if misWord == False:\n                        return True\n                    return False\n                \n                if dest[index] != origin[oIndex]:\n                    if misWord:\n                        return False\n                    misWord = True\n                    continue\n                oIndex += 1\n            return True\n        table = {}\n        def helper(node):\n            longest = 0\n            if node in table:\n                return table[node]\n            for word in words:\n                if pred(node,word):\n                    longest = max(helper(word),longest)\n            table[node] = longest + 1\n            return longest + 1\n        maxPos = 0\n        for word in words:\n            maxPos = max(maxPos,helper(word))\n        return maxPos\n", "class Solution:\n    def _check_word(self, wordlong, word2) -> bool:\n        if len(wordlong) - len(word2) > 1 or len(wordlong) - len(word2) == 0:\n            return False\n        for i in range(0, len(wordlong)):\n            newstr = wordlong[:i] + wordlong[i+1:]\n            if newstr == word2:\n                return True\n            \n        return False\n            \n        \n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) == 1:\n            return words[0]\n        \n        words = sorted(words, key=len, reverse=True)\n        \n        m = [1] * len(words)\n        for i in range(1, len(words)):\n            for j in range(0, i):\n                if self._check_word(words[j], words[i]) and m[j] + 1 > m[i]:\n                    m[i] = m[j] + 1\n        return max(m)\n                \n", "from collections import defaultdict, deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        lookup_neighbors = defaultdict(list)\n        for word in words:\n            word_length: int = len(word)\n            lookup_neighbors[word_length].append(word)\n        \n        def is_next_word_valid(current_word: str, next_word: str) -> bool:\n            current_word_length = len(current_word)\n            \n            for index in range(current_word_length):\n                if next_word == current_word[0:index] + current_word[index + 1:]:\n                    return True\n                \n            return False\n        \n        maximum_chain = 0\n        \n        for word in reversed(words):\n            frontier = deque([(word, 1)])\n            \n            while frontier:\n                next_frontier = deque()\n                while frontier:\n                    current_word, distance = frontier.popleft()\n                    current_word_length = len(current_word)\n                    maximum_chain = max(maximum_chain, distance)\n                    \n                    for neighbor in lookup_neighbors[current_word_length - 1]:\n                        if is_next_word_valid(current_word, neighbor):\n                            next_frontier.append((neighbor, distance + 1))\n                \n                frontier = next_frontier\n            \n        \n        return maximum_chain", "from collections import Counter, defaultdict\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        length_to_words = defaultdict(list)\n\n        for word in words:\n            length_to_words[len(word)].append(word)\n            \n        lengths = sorted(length_to_words.keys(), reverse=True)\n        \n        successors = defaultdict(list)\n        \n        for length in lengths:\n            for word in length_to_words[length]:\n                \n                for predecessor_candidate in length_to_words[length - 1]:\n                    if predecessor(predecessor_candidate, word):\n                        successors[predecessor_candidate].append(word)\n        \n        max_lengths = {}\n        \n        for length in lengths:\n            for word in length_to_words[length]:\n                if word in successors:\n                    max_lengths[word] = 1 + max([max_lengths[s] for s in successors[word]])\n                else:\n                    max_lengths[word] = 1\n        return max(max_lengths.values())\n                \n                \ndef predecessor(word1, word2):\n    word1_counts = Counter(word1)\n    word2_counts = Counter(word2)\n    \n    letters = set(word1 + word2)\n    \n    diff = [abs(word1_counts[l] - word2_counts[l]) for l in letters]\n    nonzero_diff = [d for d in diff if d > 0]\n    if len(nonzero_diff) != 1:\n        return False\n    if nonzero_diff[0] != 1:\n        return False\n    return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        wordsListLength = len(words)\n        if wordsListLength <= 1:\n            return wordsListLength\n        def isPredecessor(word1, word2): #is word1 predecessor of word2\n            for i in range(len(word2)):\n                if word2[:i] + word2[i+1:] == word1:\n                    return True\n            return False\n        words.sort(key = lambda x:len(x))\n        result = 1\n        dp = [1 for _ in range(wordsListLength)]\n        for i in range(wordsListLength):\n            for j in range(i + 1, wordsListLength):\n                if len(words[i]) + 1 == len(words[j]) and isPredecessor(words[i], words[j]):\n                    dp[j] = dp[i] + 1\n                    result = max(result, dp[j])\n        return result", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(str1, str2):\n            if len(str1) + 1 != len(str2):\n                return False\n            else:\n                for i in range(len(str2)):\n                    if str1 == str2[:i] + str2[i+1:]:\n                        return True\n                return False\n        l = len(words)\n        words.sort(key=len)\n        mat = [[0 for j in range(l)] for i in range(l)]\n        mat_max = 0\n        for i in range(l):\n            for j in range(i, l):\n                str1, str2 = words[i], words[j]\n                if is_predecessor(str1, str2):\n                    mat[i][j] = mat[i][i] + 1\n                    mat[j][j] = max(mat[j][j], mat[i][j])\n                    mat_max = max(mat_max, mat[i][j])\n        return mat_max + 1", "\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key = len)\n        wordCounter = [collections.Counter(x) for x in words]\n        dp = [1 for _ in range(len(words))]\n        for i in range(len(words)-2, -1, -1):\n            for j in range(i+1, len(words)):\n                if len(words[i]) == len(words[j]): continue\n                if len(words[j])-len(words[i]) > 1: break\n                if len(wordCounter[j] - wordCounter[i]) == 1:\n                    dp[i] = max(dp[i], dp[j]+1)\n        return max(dp)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        dic = collections.Counter()\n        res = 0\n        for word in words:\n            for i in range(len(word)):\n                pre = word[:i] + word[i + 1:]\n                dic[word] = max(dic[word], dic[pre] + 1)\n            res = max(res, dic[word])\n        return res\n", "class Solution:\n    def one_off(self, a, b):\n        if abs(len(a)-len(b)) != 1:\n            return False\n        one_off = False\n        i = 0\n        j = 0\n        while i < len(a) and j < len(b):\n            if a[i]!=b[j]:\n                if one_off:\n                    return False\n                one_off = True\n                if len(a) > len(b):\n                    j-=1\n                else:\n                    i-=1\n            i+=1\n            j+=1\n        \n        return True\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        words.sort(key=lambda word: -len(word))\n        # print(words)\n        dp = {}\n        # prev = {}\n        best = 1\n        for i, word in enumerate(words):\n            for other in words[i+1:]:\n                if len(word) - 1 > len(other):\n                    break\n                if self.one_off(word, other):\n                    dp[other] = max(dp.get(other, 0), dp.get(word, 1)+1)\n                    # if dp[other] > best:\n                    #     prev[other] = word\n                    best = max(best, dp[other])\n        # print(prev)           \n        return best", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def is_predecessor(str1, str2):\n            if len(str1) + 1 != len(str2):\n                return False\n            else:\n                for i in range(len(str2)):\n                    if str1 == str2[:i] + str2[i+1:]:\n                        return True\n                return False        \n        #words = [\\\"sgtnz\\\",\\\"sgtz\\\",\\\"sgz\\\",\\\"ikrcyoglz\\\",\\\"ajelpkpx\\\",\\\\\n                #\\\"ajelpkpxm\\\",\\\"srqgtnz\\\",\\\"srqgotnz\\\",\\\"srgtnz\\\",\\\"ijkrcyoglz\\\"]\n        l = len(words)\n        words.sort(key=len)\n        mat = [[0 for j in range(l)] for i in range(l)]\n        mat_max = 0\n        for i in range(l):\n            for j in range(i, l):\n                str1, str2 = words[i], words[j]\n                if is_predecessor(str1, str2):\n                    mat[i][j] = mat[i][i] + 1\n                    mat[j][j] = max(mat[j][j], mat[i][j])\n                    mat_max = max(mat_max, mat[i][j])\n        return mat_max + 1", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) <= 0:\n            return 0\n        \n        words.sort(key=len)\n        numberOfWords = len(words)\n        longestLens = [1] * len(words)\n        index = numberOfWords - 1    \n        ret = 0\n        while index >= 0:\n            maxLen = 1\n            index2 = index + 1\n            while index2 < numberOfWords and len(words[index]) + 1 >= len(words[index2]):\n                if self.isPredecessor(words[index], words[index2]):\n                    if maxLen < longestLens[index2] + 1:\n                        maxLen = longestLens[index2] + 1\n                index2 += 1\n            longestLens[index] = maxLen\n            if ret < maxLen:\n                ret = maxLen\n            index -= 1\n        \n        return ret\n                    \n    \n    def isPredecessor(self, word1:str, word2:str)-> bool:\n        if len(word2) - len(word1) != 1:\n            return False\n        for i, ch in enumerate(word2):\n            newWord = word2[:i] + word2[i+1:]\n            if newWord == word1:\n                return True\n        return False\n    \n        \n", "from collections import Counter\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda x: len(x))\n        def check_predecessor(s1, s2):\n            if len(s1) != len(s2) - 1:\n                return False\n            for i in range(len(s2)):\n                if s1 == (s2[:i] + s2[i+1:]):\n                    return True\n            return False\n        \n        dp = [1] * len(words)\n        res = 1\n        \n        for i in range(len(words)):\n            for j in range(i):\n                if check_predecessor(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j]+1)\n                    res = max(res, dp[i])\n                    \n        return res\n                    \n                    \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n    \n        # build graph out of all pairs of words\n        graph = defaultdict(list)\n        in_degrees = defaultdict(int)\n        for w1 in words:\n            for w2 in words:\n                if self.isPredecessor(w1, w2):\n                    # w1 have more words -> w2->w1\n                    graph[w2].append(w1)\n                    in_degrees[w1] += 1\n        \n        max_len = 1\n        # topological sort to get the maximum length ending with each word\n        queue = deque([(w, 1) for w in graph if in_degrees[w] == 0])\n        while queue:\n            word, path_len = queue.popleft()\n            for child in graph[word]:\n                in_degrees[child] -= 1\n                if in_degrees[child] == 0:\n                    queue.append((child, path_len + 1))\n            \n            max_len = path_len\n        return max_len\n        \n\n    def isPredecessor(self, w1, w2):\n        if len(w1) != len(w2) + 1:\n            return False\n        \n        i1 = 0\n        i2 = 0\n        added = False\n        while i1 < len(w1) and i2 < len(w2):\n            if w1[i1] != w2[i2] and added:\n                return False\n            elif w1[i1] != w2[i2]:\n                i1 += 1\n                added = True\n            else:\n                i1 += 1\n                i2 += 1\n\n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) <= 0:\n            return 0\n        \n        words.sort(key=len)\n        numberOfWords = len(words)\n        longestLens = [1] * len(words)\n        index = numberOfWords - 1\n        \n        while index >= 0:\n            maxLen = 1\n            index2 = index + 1\n            while index2 < numberOfWords and len(words[index]) + 1 >= len(words[index2]):\n                if self.isPredecessor(words[index], words[index2]):\n                    if maxLen < longestLens[index2] + 1:\n                        maxLen = longestLens[index2] + 1\n                index2 += 1\n            longestLens[index] = maxLen\n            index -= 1\n        \n        maxLen = longestLens[0]\n        for longestLen in longestLens:\n            if maxLen < longestLen:\n                maxLen = longestLen\n        return maxLen\n                    \n    \n    def isPredecessor(self, word1:str, word2:str)-> bool:\n        if len(word2) - len(word1) != 1:\n            return False\n        for i, ch in enumerate(word2):\n            newWord = word2[:i] + word2[i+1:]\n            if newWord == word1:\n                return True\n        return False\n    \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        longestchain = defaultdict(int)\n        for word in sorted(words, key=len, reverse=True):\n            for i in range(len(word)):\n                longestchain[word[:i] + word[i + 1:]] = max(longestchain[word[:i] + word[i + 1:]], 1 + longestchain[word])\n        return max(longestchain.values()) \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        sorted(words, key = len, reverse = True)\n        depth = [1] * len(words)\n        def dfs(word):\n            depth = 1\n            for i in range(len(word)):\n                new_word = word[:i]+word[i+1:]\n                if new_word in words:\n                    depth = max(dfs(new_word)+1, depth)\n            seen.append(word)\n            return depth\n        \n        count = []\n        seen = []\n        for word in words:\n            if word not in seen:\n                count.append(dfs(word))\n        return max(count)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        l = [1 for i in range(len(words))]\n        words = list(set(words))\n        words.sort(key = lambda x:len(x))\n        res = [[i] for i in words]\n        # print(l,res)\n        for i in range(1,len(words)):\n            for j in range(i):\n                if len(words[j])+1==len(words[i]):\n                    x = {}\n                    for a in words[j]:\n                        if a in x:\n                            x[a]+=1\n                        else:\n                            x[a]=1\n                    ctr = 0\n                    for a in words[i]:\n                        if a not in x:\n                            ctr+=1\n                        elif x[a]==0:\n                            ctr+=1\n                        else:\n                            x[a]-=1\n                    if ctr==1 and l[i]<(l[j]+1):\n                        res[i] = [i for i in res[j]]\n                        res[i].append([words[i]])\n                        l[i] = l[j]+1\n        return max(l)\n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        preToPost = collections.defaultdict(set)\n        for word1 in words:\n            for word2 in words:\n                if self.isPredecessor(word1, word2):\n                    preToPost[word1].add(word2)\n        \n        ans = 0\n        memo = {}\n        for word in words:\n            ans = max(ans, self.dfs(word, preToPost, memo))\n        return ans\n        \n        \n        \n    \n    def dfs(self, word, preToPost, memo):\n        if word in memo:\n            return memo[word]\n        \n        # if word not in preToPost:\n        #     memo[word] = 1\n        #     return memo[word]\n        \n        ans = 1\n        for post in preToPost[word]:\n            ans = max(ans, 1 + self.dfs(post, preToPost, memo))\n        \n        memo[word] = ans\n        return memo[word]\n    \n    \n    def isPredecessor(self, word1, word2):\n        if not len(word1) + 1 == len(word2):\n            return False \n        \n        missed = False\n        i = 0\n        j = 0\n        while i < len(word1) and j < len(word2) and word1[i] == word2[j]:\n            i += 1\n            j += 1\n        \n        j += 1\n        \n        while i < len(word1) and j < len(word2) and word1[i] == word2[j]:\n            i += 1\n            j += 1\n        \n        return i == len(word1) and j == len(word2)", "\nclass Solution:\n    def longestStrChain(self, words) -> int:\n        len_words = len(words)\n        dp = [1] * len_words\n        res = 0\n        words.sort(key = len)\n        for i in range(len_words):\n            max_value = 0\n            for j in range(i):\n                if not self.checkChild(words[j], words[i]):\n                    continue\n                max_value = max(max_value, dp[j])\n            dp[i] = max_value + 1\n            res = max(res, dp[i])\n        return res\n\n    def checkChild(self, word1, word2):\n        if len(word1) != len(word2) - 1:\n            return False\n        from collections import Counter\n        counter1 = Counter(word1)\n        count = 0\n        for ch in word2:\n            if ch in counter1:\n                counter1[ch] -= 1\n                if counter1[ch] == 0:\n                    counter1.pop(ch)\n            else:\n                count += 1\n            if count > 1:\n                return False\n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPredecessor(word1, word2):\n            if len(word1) + 1 != len(word2):\n                return False\n            i, j, count = 0, 0, 0\n            while i < len(word1):\n                if word1[i] != word2[j]:\n                    count += 1\n                    j += 1\n                    if count > 1:\n                        return False\n                    continue\n                i += 1\n                j += 1\n            return True\n        \n        # build graph\n        numPredecessor = [0] * len(words)\n        \n        graph = defaultdict(lambda: [])\n        for i in range(len(words)):\n            for j in range(i + 1, len(words)):\n                if isPredecessor(words[i], words[j]):\n                    graph[i].append(j)\n                    numPredecessor[j] += 1\n                elif isPredecessor(words[j], words[i]):\n                    graph[j].append(i)\n                    numPredecessor[i] += 1\n        \n        # dfs for each node without predecessor\n        def dfs(node, path):\n            nonlocal out\n            \n            path.append(node)\n            out = max(out, len(path))\n            for nei in graph[node]:\n                dfs(nei,path)\n            path.pop()\n            \n        \n        out = 0\n        for node in [i for i in range(len(words)) if not numPredecessor[i]]:\n            dfs(node,[])\n        return out\n        \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        children = collections.defaultdict(set)\n        for i in range(len(words)):\n            for j in range(len(words)):\n                if len(words[i]) == len(words[j]) + 1:\n                    for k in range(len(words[i])):\n                        if words[i][:k] + words[i][k+1:] == words[j]:\n                            children[words[j]].add(words[i])\n        print(children)\n        def dfs(w, count):\n            visited.add(w)\n            if not children[w]:\n                self.res = max(self.res, count)\n            else:\n                for v in children[w]:\n                    dfs(v, count + 1)\n        visited = set()\n        self.res = 0\n        for u in words:\n            if u not in visited:\n                dfs(u, 1)\n        return self.res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPredecessor(word1, word2):\n            if len(word1) + 1 != len(word2):\n                return False\n            i, j, count = 0, 0, 0\n            while i < len(word1):\n                if word1[i] != word2[j]:\n                    count += 1\n                    j += 1\n                    if count > 1:\n                        return False\n                    continue\n                i += 1\n                j += 1\n            return True\n        \n        # build graph\n        numPredecessor = [0] * len(words)\n        \n        graph = defaultdict(lambda: [])\n        for i in range(len(words)):\n            for j in range(i + 1, len(words)):\n                if isPredecessor(words[i], words[j]):\n                    graph[i].append(j)\n                    numPredecessor[j] += 1\n                elif isPredecessor(words[j], words[i]):\n                    graph[j].append(i)\n                    numPredecessor[i] += 1\n        \n        # dfs for each node without predecessor\n        def dfs(node, path):\n            nonlocal out\n            \n            path.append(node)\n            out = max(out, len(path))\n            for nei in graph[node]:\n                dfs(nei,path)\n            path.pop()\n            \n        \n        out = 0\n        for node in [i for i in range(len(words)) if not numPredecessor[i]]:\n            if out == 16:\n                break\n            dfs(node,[])\n        return out\n        \n        \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        word_map = collections.defaultdict(int)\n        word_list = collections.defaultdict(list)\n        ans = 1\n        #\u6ca1\u6709\u4efb\u4f55\u5148\u5bfc\u5355\u8bcd\u7684\u8bdd\uff0cis_predecessor \u6c38\u8fdc\u8fd4\u56defalse, \u8fd9\u6837\u957f\u5ea6\u81f3\u5c11\u4e3a1\n        for word in words:\n            length = len(word)\n            word_list[length].append(word)\n            word_map[word] = 1\n        \n        # print(word_map)\n        for word_len in range(1, 17):\n            if word_len not in word_list:\n                continue\n            for word in word_list[word_len]:\n                pre_len = word_len - 1\n                if pre_len not in word_list:\n                    break\n                for pre_word in word_list[pre_len]:\n                    if self.is_predecessor(pre_word, word):\n                        word_map[word] = max(word_map[word], word_map[pre_word] + 1)\n                        ans = max(ans, word_map[word])\n        \n        return ans\n    \n    def is_predecessor(self, w1, w2):\n        idx1, idx2 = 0, 0\n        once = False\n        while idx1 < len(w1) and idx2 < len(w2):\n            if w1[idx1] == w2[idx2]:\n                idx1 += 1\n                idx2 += 1\n            elif once:\n                return False\n            else:\n                once = True\n                idx2 += 1\n        \n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def isPredecessor(word1, word2):\n            if len(word1) + 1 != len(word2):\n                return False\n            i, j = 0, 0\n            while i < len(word1):\n                if word1[i] != word2[j]:\n                    j += 1\n                    if j-i > 1:\n                        return False\n                    continue\n                i += 1\n                j += 1\n            return True\n        \n        # build graph\n        numPredecessor = [0] * len(words)\n        \n        graph = defaultdict(lambda: [])\n        for i in range(len(words)):\n            for j in range(i + 1, len(words)):\n                if isPredecessor(words[i], words[j]):\n                    graph[i].append(j)\n                    numPredecessor[j] += 1\n                elif isPredecessor(words[j], words[i]):\n                    graph[j].append(i)\n                    numPredecessor[i] += 1\n        \n        # dfs for each node without predecessor\n        def dfs(node, path):\n            nonlocal out\n            \n            path.append(node)\n            out = max(out, len(path))\n            for nei in graph[node]:\n                dfs(nei,path)\n            path.pop()\n            \n        \n        out = 0\n        for node in [i for i in range(len(words)) if not numPredecessor[i]]:\n            if out == 16:\n                break\n            dfs(node,[])\n        return out\n        \n        \n        \n", "from collections import defaultdict\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        #idea is to sort words based on length and then apply dfs on each index\n        n = len(words)\n        words.sort(key=len)\n        memo = {}\n        \n        def check_pred(word1,word2):\n            if len(word2) - len(word1) != 1:\n                return False\n            for i in range(len(word2)):\n                pred_str = word2[0:i] + word2[i+1:]\n                if word1 == pred_str:\n                    return True\n            return False\n        \n        def recur(start):\n            if start in memo:\n                return memo[start]\n            f_max = 1\n            for i in range(start+1,n):\n                c_max = 1\n                if check_pred(words[start], words[i]):\n                    c_max = 1 + recur(i)\n                f_max = max(f_max,c_max)\n            memo[start] = f_max\n            return f_max\n        \n        ans = 0\n        for i in range(n):\n            ans = max(ans, recur(i))\n        return ans\n                    \n                \n", "from collections import defaultdict\nclass Solution:\n    def is_neighbor(self, s1, s2):\n        ss = s1\n        bs = s2\n        neighbor = False\n\n        for i in range(len(ss) + 1):\n            padded_str = ss[:i] + '*' + ss[i:]\n\n            for p1, p2 in zip(padded_str, bs):\n                # print((p1 == '*' or p1 == p2))\n                neighbor = (p1 == '*' or p1 == p2)\n                if not neighbor:\n                    break\n            if neighbor:\n                return neighbor\n\n    path_len = 1\n\n    def build_chains(self, chain_graph, start_key, visited=set(), curr_path=2):\n        # print(curr_path_len, start_key)\n        visited.add(start_key)\n        # print(start_key, curr_path)\n        for string in chain_graph[start_key] - visited:\n            if string in chain_graph:\n                self.build_chains(chain_graph, string, visited, curr_path + 1)\n            else:\n                print(('term:', string, curr_path+1))\n                self.path_len = max(self.path_len, curr_path+1)\n\n    def longestStrChain(self, words: List[str]) -> int:\n        str_chain_graph = defaultdict(set)\n        for w1 in words:\n            for w2 in words:\n                if len(w2) - len(w1) == 1:\n                    neighbor = self.is_neighbor(w1, w2)\n                    if neighbor:\n                        str_chain_graph[w1].add(w2)\n        # print(str_chain_graph)\n        for key in str_chain_graph:\n            self.build_chains(str_chain_graph, key, set(), 1)\n        return self.path_len\n", "class Solution:\n    def string1(self,s1,s2):\n        if  abs(len(s1)-len(s2))>1 or abs(len(s1)-len(s2))==0:\n            return False\n        i=0\n        j=0\n        k=0\n        while i<len(s1) and j<len(s2):\n            if k>1:return False\n            if s1[i]!=s2[j]:\n                k+=1\n                if len(s1)>len(s2):\n                    i+=1\n                else:\n                    j+=1\n            else:\n                i+=1\n                j+=1\n        return True if k<=1 else False\n    def longestStrChain(self, words: List[str]) -> int:\n        words= sorted(words,key=len,reverse=True)\n        d={}\n        l=len(words[0])\n        m=1\n        for i in range(len(words)):\n            w=words[i]\n            m=max([m]+list(d.values()))\n            d={key:val for key,val in list(d.items()) if len(key)<=len(w)+1}\n            d[w]=1\n            for key,val in list(d.items()):\n                if self.string1(key,w):\n                    d[w]=max(d[w],d[key]+1)\n            l=len(w)\n        return max([m]+list(d.values()))\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def isPred(w1, w2):\n            if len(w1) + 1 != len(w2):\n                return False\n            flag = 0\n            \n            for i in range(len(w1)):\n                if w1[i] != w2[i + flag] and flag == 0:\n                    flag = 1\n                    if w1[i] != w2[i + flag]:\n                        return False\n                elif w1[i] != w2[i + flag] and flag != 0:\n                    return False\n            return True\n                    \n        \n        \n        def dfs(i):\n            if i in memo:\n                return memo[i]\n            \n            max_level = 0\n            for next_i in graph[i]:\n                level = dfs(next_i)\n                if level > max_level:\n                    max_level = level\n            memo[i] = max_level + 1\n            return memo[i]\n        \n        n = len(words)\n        if n <= 1:\n            return n\n        \n        graph = collections.defaultdict(list)\n        \n        for i in range(n):\n            for j in range(n):\n                if isPred(words[i], words[j]):\n                    graph[i].append(j)\n        #graph, time: O(n*n*k), space(n*n*k)\n        memo = {}\n        ans = 0\n        for i in range(n):\n            level = dfs(i)\n            if level > ans:\n                ans = level\n        #dfs, time: O(n), space(n)\n        return ans\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        cache = {}\n        words_dict = {word:None for word in words}\n        def chain(word):\n            if word in cache: return cache[word]\n            if word in words:\n                cache[word] = 1 + max(\n                    map(chain, [word[:idx]+word[idx+1:] for idx in range(len(word))])\n                )\n                return cache[word]\n            return 0\n        return max(map(chain, words))", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def custom_equal(word1, word2):\n            if len(word2) == len(word1): return 0\n            for i in range(len(word2)):\n                if word2[0:i] + word2[i+1:] == word1:\n                    return 1\n                \n            return 0\n        \n        words.sort(key=lambda x: len(x))\n        max_len = 1\n        # maximum length ending at index i\n        dp = [1 for _ in words]\n        for i in range(1, len(words)):\n            for j in range(i-1, -1, -1):\n                # judge if word[j] is a predecessor of word[i]\n                if len(words[j])+1 < len(words[i]):\n                    break\n                if custom_equal(words[j], words[i]):\n                    dp[i] = max(dp[i], dp[j]+1)\n                max_len = max(max_len, dp[i])\n                \n        return max_len\n    \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        ans, dicti, memo = 0, collections.defaultdict(list), collections.defaultdict(int)\n        for word in words:\n            dicti[len(word)].append(word)\n        chars = [chr(ch) for ch in range(ord('a'), ord('z')+1)]\n        \n        def find(count, word):\n            if word in memo:\n                return count + memo[word]\n            if len(word) + 1 not in dicti:\n                memo[word] = 0\n                return count\n                \n            maxi = 0\n            for i in range(len(word)+1):\n                for ch in chars:\n                    new_word = word[:i] + ch + word[i:]\n                    if new_word in dicti[len(word)+1]:\n                        maxi = max(maxi, find(1, new_word))\n            memo[word] = maxi\n            return count + memo[word]\n        \n        for word in sorted(words, key=lambda x:len(x)):\n            el = find(1, word)\n            # print(el, word)\n            ans = max(ans, el)\n        return ans\n\n            \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        n = len(words)\n        lis = defaultdict(int)\n        # print(lis)\n        words = sorted(words, key=len)\n        print(words)\n        ans = 0\n        for i in range(n):\n                w = words[i]\n                # lis[w] = 1\n                for j in range(len(words[i])):\n                    s = w[0:j] + w[j+1:]\n                    lis[w] = max(lis[w], lis[s] + 1)\n                    \n                ans = max(ans, lis[w])\n        \n        \n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n#         words.sort(key=len)\n        \n#         dp = {}\n#         ans = 1\n        \n#         for word in words:\n#             dp[word] = 1\n#             for i in range(len(word)):\n#                 cand = word[:i] + word[i+1:]\n#                 if cand in dp:\n#                     dp[word] = max(dp[word], dp[cand] + 1)\n#                     ans = max(ans, dp[word])    \n#         return ans\n               \n        if not words:\n            return 0\n        \n        self.memo = {}\n        self.ans = 1\n        self.words = set(words)\n        for word in self.words:\n            self.dfs(word)\n        return self.ans\n        \n    def dfs(self, word):   \n        if len(word) == 1:\n            self.memo[word] = 1\n            return 1\n                \n        self.memo[word] = 1\n        for i in range(len(word)):\n            nxt = word[:i] + word[i+1:]\n            if nxt in self.words:\n                self.memo[word] = max(self.memo[word], 1+self.dfs(nxt))\n                self.ans = max(self.ans, self.memo[word])\n        return self.memo[word]", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n#         words.sort(key=len)\n        \n#         dp = {}\n#         ans = 1\n        \n#         for word in words:\n#             dp[word] = 1\n#             for i in range(len(word)):\n#                 cand = word[:i] + word[i+1:]\n#                 if cand in dp:\n#                     dp[word] = max(dp[word], dp[cand] + 1)\n#                     ans = max(ans, dp[word])    \n#         return ans\n               \n        if not words:\n            return 0\n        \n        self.memo = {}\n        self.ans = 1\n        self.words = set(words)\n        for word in self.words:\n            self.dfs(word, 1)\n        return self.ans\n        \n    def dfs(self, word, count):   \n        if len(word) == 1:\n            self.memo[word] = 1\n            return 1\n                \n        self.memo[word] = 1\n        for i in range(len(word)):\n            nxt = word[:i] + word[i+1:]\n            if nxt in self.words:\n                self.memo[word] = max(self.memo[word], 1+self.dfs(nxt, count + 1))\n                self.ans = max(self.ans, self.memo[word])\n        return self.memo[word]", "from collections import defaultdict\n\nclass Solution:\n    def is_one_apart(self, word1, word2):\n        assert len(word1) >= len(word2)\n        \n        length_diff = len(word1) - len(word2)\n        if length_diff != 1:\n            return False\n        \n        i = 0\n        j = 0\n        while i < len(word1) and j < len(word2):\n            if word1[i] == word2[j]:\n                i += 1\n                j += 1\n            elif i - j >= 1:\n                return False\n            else:\n                i += 1\n        \n        return True\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        length_words = defaultdict(list)\n        chain_lengths = {}\n        max_chain = 1\n        \n        for word in words:\n            length_words[len(word)].append(word)\n            chain_lengths[word] = 1\n        \n        for length in sorted(list(length_words.keys()), reverse=True):\n            if length - 1 not in length_words:\n                continue\n            \n            for word1 in length_words[length]:\n                for word2 in length_words[length - 1]:\n                    if chain_lengths[word1] + 1 <= chain_lengths[word2]:\n                        continue\n                    \n                    if self.is_one_apart(word1, word2):\n                        chain_lengths[word2] = chain_lengths[word1] + 1\n                        max_chain = max(max_chain, chain_lengths[word2])\n        \n        # print(chain_lengths)\n        \n        return max_chain\n        \n", "class Solution:\n    def checkPre(self, small, large):\n        \n        i = 0\n        j = -1\n        \n        while True:\n            l = r = True\n            if i < len(small) and small[i] == large[i]:\n                i += 1\n            else:\n                l = False\n            \n            if j + len(small) >= 0 and small[j] == large[j]:\n                j -= 1\n            else:\n                r = False\n            \n            if not l and not r:\n                break\n        \n        return i - j >= len(large)\n        \n    def longestStrChain(self, words: List[str]) -> int:\n        table = dict()\n        small = 10000\n        large = 0\n        \n        for i in range(len(words)):\n            length = len(words[i])\n            if length not in table:\n                small = min(length, small)\n                large = max(length, large)\n                table[length] = [i]\n            else:\n                table[length].append(i)\n        \n        pre = [1 for i in range(len(words))]\n        for i in range(small, large):\n            for j in range(len(table[i])):\n                for k in range(len(table[i + 1])):\n                    if self.checkPre(words[table[i][j]], words[table[i + 1][k]]):\n                        pre[table[i + 1][k]] = max(pre[table[i + 1][k]], pre[table[i][j]] + 1)\n                        \n        return max(pre)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        '''\n        DFS with memo\n        '''\n        words = set(words)\n        dp = {}\n        def chainEndingAt(word):\n            if word not in words:\n                return 0\n            if word not in dp:\n                chain_len = 1\n                for i in range(len(word)):\n                    pred = word[:i] + word[i+1:]\n                    chain_len = max(chain_len, chainEndingAt(pred) + 1)\n                dp[word] = chain_len\n            return dp[word]\n        return max(chainEndingAt(word) for word in words)\n        \n        '''\n        DP\n        dp function:\n        chain[word2] = max(chain[word1]+1 for all word1 if word1 is predecessor of word2)\n        '''\n        dp = {}\n        for w in sorted(words, key=len):\n            dp[w] = 1\n            for i in range(len(w)):\n                dp[w] = max(dp[w], dp.get(w[:i] + w[i+1:],0) + 1)\n        return max(dp.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        visited = set()\n        word_dict = {}\n        \n        for word in words:\n            word_dict[word] = 1\n        \n        def visit(word):\n            visited.add(word)\n            \n            for i in range(len(word)):\n                child = word[:i] + word[i+1:]\n                if child not in word_dict:\n                    continue\n                \n                if child not in visited:\n                    visit(child)\n                \n                word_dict[word] = max(word_dict[word], 1 + word_dict[child])    \n        \n        for word in words:\n            visit(word)\n        \n        return max(word_dict.values())\n\n                    \n        \n            \n", "class Solution:\n    def match(self, small, big):\n        mismatch = 0\n        i = 0\n        while i < len(small):\n            j = i + mismatch\n            \n            if small[i] == big[j]:\n                i+=1\n                continue\n            elif not mismatch:\n                mismatch = 1\n            elif mismatch==1:\n                return False\n        \n        return True\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        \n        # sort by length\n        if len(words) == 1:\n            return 1\n        len_counts = {}\n        min_len = 17\n        \n        for w in words:\n            l = len(w)\n            if l not in len_counts:\n                len_counts[l] = [w]\n                if l < min_len:\n                    min_len = l\n            else:\n                len_counts[l].append(w)\n        \n        # keep track of the last link, and count\n        chains = {}\n        \n        # start the chains with the smallest words\n        for w in len_counts[min_len]:\n            chains[w] = 1\n        ans = -1\n        \n        keys = sorted(list(len_counts.keys()))\n        prev_len = keys[0]\n        for l in keys[1:]:\n            \n            # get all words of this length\n            poss = len_counts[l]\n            if l != prev_len + 1:\n                prev_len = l\n                \n                # just add these to dict\n                for w in poss:\n                    if w not in chains:\n                        chains[w] = 1\n                        \n                continue\n                \n            poss_last = len_counts[prev_len]\n            \n            # print(poss, poss_last)\n            for w in poss:\n                if w not in chains:\n                    chains[w] = 1\n\n                #check for each word less than this\n                for last in poss_last:\n                    if self.match(last, w):\n                        chains[w] = max(chains[w], chains[last]+1)\n            \n            prev_len = l\n        # return max value in chains\n        # print(chains)\n        return max(chains.values())\n                \n        \n        \n            \n        \n", "class Solution:\n    def isPredecessor(self, s1, s2):\n        if len(s2) - len(s1) != 1: return False\n        newcharfound = False\n        for i in range(len(s2)):\n            if not newcharfound:\n                if i == len(s1): return True\n                if s1[i] != s2[i]:\n                    newcharfound = True\n                    j = i\n            else:\n                if s1[j] != s2[i]:\n                    return False\n                j += 1\n        return True\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        \n        lentoword = collections.defaultdict(list)\n        for i,w in enumerate(words):\n            lentoword[len(w)].append((w,i))\n\n        dp = [1 for i in range(len(words)+1)]\n        dp[0] = 0 \n\n        for i in range(1, len(words) + 1): \n            word = words[i-1]\n            curlen = len(words[i-1])\n            for nbor, nborindex in lentoword[curlen-1]:\n                if self.isPredecessor(nbor, word):\n                    dp[i] = max(dp[i], dp[nborindex+1] +1)\n        return max(dp)\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        word_dict = defaultdict(int)\n        longest = 0\n        \n        for word in words:\n            for i in range(len(word)):\n                wc = word[:i ] + word[i+1:]\n                word_dict[word] = max(word_dict[wc]+1, word_dict[word])\n            longest = max(longest, word_dict[word])\n        return longest", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        def dfs(cur):\n            if cur not in s:\n                return 0\n            if len(cur) == 0:\n                return 0\n            if cur in d:\n                return d[cur]\n            res = 1\n            for i in range(len(cur)):\n                t = cur[:i] + cur[i+1:]\n                res = max(dfs(t)+1, res)\n            d[cur] = res\n            return d[cur]\n            \n        s = set(words) \n        d = {}\n        _max = 0\n        for w in words:\n            _max = max(dfs(w), _max)\n        return _max\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if len(words) == 0:\n            return 0\n        adj = {}\n        for w in words:\n            for i in range(len(w)):\n                s = w[0:i] + w[i+1:]\n                if s not in adj:\n                    adj[s] = [w]\n                else:\n                    adj[s].append(w)\n        res = 1\n        queue = []\n        visited = {}\n        def dfs(root):\n            if root in visited:\n                return visited[root]\n            if root not in adj:\n                visited[root] = 1\n                return 1\n            distance = 1\n            for next_ in adj[root]:\n                distance = max(distance, dfs(next_)+1)\n            visited[root] = distance\n            return distance\n        for w in words:\n            length = dfs(w)\n            res = max(res, length)\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = collections.defaultdict(int)\n        for w in sorted(words, key = len):\n            for i in range(len(w)):\n                dp[w] = max(dp[w], 1 +  dp[w[:i] + w[i + 1:]])\n        return max(dp.values())\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        graph = {}\n        max_dist = 0\n        for word in words:\n            length = len(word)\n            dist = 0\n            for i in range(length):\n                if (check := word[:i] + word[i+1:]) in graph:\n                    dist = max(graph[check], dist)\n                graph[word] = dist+1\n                max_dist = max(max_dist, graph[word])\n        return max_dist", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = collections.defaultdict(int)\n        \n        for word in sorted(words, key=len):\n            for i in range(len(word)):\n                dp[word] = max(dp[word], dp[word[:i] + word[i+1:]] + 1)\n        return max(dp.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = set(words)\n        @lru_cache()\n        def helper(word):\n            if not word or word not in words: \n                return 0\n            return 1 + max(helper(word[:i] + word[i + 1:]) for i in range(len(word)))\n        return max(helper(word) for word in words)", "from functools import lru_cache\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        @lru_cache\n        def chain_len(w):\n            return 1 + max(chain_len(w[:i] + w[i+1:]) for i in range(len(w))) if w in valid else 0\n        \n        valid = set(words)\n        return max(chain_len(w) for w in words)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        ans = defaultdict(int)\n        words.sort(key=len)\n        for s in words:\n            n = len(s)\n            now = 0\n            for i in range(n):\n                s1, s2 = s[:i], s[i+1:]\n                now = max(now, ans[(s1, s2)])\n            now += 1\n            for i in range(n+1):\n                s1, s2 = s[:i], s[i:]\n                ans[(s1, s2)] = now\n        return max(ans.values())", "from functools import lru_cache\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        @lru_cache\n        def chain_len(word):\n            return 1 + max(chain_len(word[:i] + word[i+1:]) for i in range(len(word))) if word in valid else 0\n        \n        valid = set(words)\n        return max(chain_len(word) for word in words)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        res = 0\n        dic = collections.defaultdict(int)\n        words.sort(key=lambda x : len(x))\n        for w in words:\n            m = len(w)\n            for i in range(m):\n                new = w[:i] + w[i + 1:]\n                dic[w] = max(dic[w], dic[new] + 1)\n            res = max(res, dic[w])\n        return res", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        wc = {}\n        for w in words:\n            wc.setdefault(len(w), [])\n            wc[len(w)].append(w)\n        \n        d = {}\n        for i in sorted(wc.keys()):\n            if i - 1 not in wc:\n                for w in wc[i]:\n                    d[w] = 1\n            else:\n                for w in wc[i]:\n                    d[w] = 1\n                    for i in range(len(w)):\n                        if w[:i] + w[i+1:] in d:\n                            d[w] = max(d[w], d[w[:i] + w[i+1:]] + 1)\n        return max(d.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        wordSet = set(words)\n        i_min = min(wordSet)\n        @lru_cache()\n        def aux(word):\n            if not word or word not in wordSet: return 0\n            if len(word) == i_min: return 1\n            return 1+max(aux(word[:i]+word[i+1:]) for i in range(len(word)))\n        return max(aux(w) for w in words)", "import copy\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=lambda word: len(word), reverse=True)\n        wordSet = set(copy.deepcopy(words))\n        visited = set()\n        \n        def find_chain(word, length):\n            if word not in wordSet or word in visited:\n                return length\n            \n            visited.add(word)\n            max_len = 0\n            for i in range(len(word)):\n                tmp = copy.deepcopy(word)\n                tmp = tmp[:i] + tmp[i+1:]\n                \n                max_len = max(find_chain(tmp, length+1), max_len)\n                \n            return max_len\n        \n        max_len = 0\n        for word in words:\n            max_len = max(max_len, find_chain(word, 0))\n        \n        return max_len\n        \n            \n                \n", "class Solution:\n    def predecessor(self, word_1, word_2):\n        if abs(len(word_1)-len(word_2)) != 1: return False\n        idx_1 = 0\n        idx_2 = 0\n        while(idx_1 < len(word_1) and idx_2 < len(word_2)):\n            if word_1[idx_1] != word_2[idx_2]:\n                if idx_1 != idx_2: return False\n                if len(word_1) < len(word_2): idx_2 += 1\n                else: idx_1 += 1\n            else:\n                idx_1 += 1\n                idx_2 += 1\n        return True\n    def longestStrChain(self, words: List[str]) -> int:\n        dict = {}\n        dp = [1 for i in range(0, len(words))]\n        words.sort(key=len)\n        for i in range(0, len(words)):\n            words[i] = ''.join(sorted(words[i]))\n            if len(words[i]) in list(dict.keys()): dict[len(words[i])].append(i)\n            else: dict[len(words[i])] = [i]\n        for i in range(0, len(words)):\n            if len(words[i])+1 in list(dict.keys()):\n                for elem in dict[len(words[i])+1]:\n                    if self.predecessor(words[elem], words[i]): dp[elem] = max(dp[elem], dp[i]+1)\n        ans = 0\n        for i in range(0, len(dp)): ans = max(ans, dp[i])\n        return ans\n            \n       \n        \n        \n            \n            \n        \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words = set(words)\n        @lru_cache()\n        def aux(word):\n            if not word or word not in words: return 0\n            return 1+max(aux(word[:i]+word[i+1:]) for i in range(len(word)))\n        return max(aux(w) for w in words)", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        from collections import defaultdict\n        words.sort(key=lambda word:len(word), reverse=True)\n        length = defaultdict(int)\n        longest = 0\n        for word in words:\n            length[word] = max(length[word], 1)\n            longest = max(longest, length[word])\n            for i in range(len(word)):\n                length[word[:i] + word[i+1:]] = max(length[word[:i] + word[i+1:]], length[word] + 1)\n        return longest", "from collections import defaultdict, deque\n\nclass Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        \n        words_set = set(words)\n        \n        def helper(word):\n            \n            if len(word) == 0:\n                return 0\n            \n            for index in range(len(word)):\n                \n                string = word[:index] + word[index + 1:]\n                \n                if string not in maxChain and string in words_set:\n                    helper(string)\n                \n                maxChain[word] = max(maxChain[word], maxChain[string] + 1)\n                \n            return maxChain[word]\n        \n        maxChain = defaultdict(lambda: 0)\n                \n        for word in words:\n            \n            maxVal = 0\n            \n            if word not in maxChain:\n                helper(word)\n\n        return max(maxChain.values())\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        words.sort(key=len)\n        longest = 0\n        word_dict = defaultdict(int)\n        \n        \n        for word in words:\n            for i in range(len(word)):\n                wc = word[:i] + word[i+1:]\n                word_dict[word] = max(word_dict[wc] + 1, word_dict[word])\n                \n            longest = max(longest, word_dict[word])\n        return longest", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        '''\n        DFS with memo\n        '''\n        words = set(words)\n        dp = {}\n        \n        def chainEndingAt(word):\n            if word not in words:\n                return 0\n            # if memo\n            chain_len = 1\n            for i in range(len(word)):\n                pred = word[:i] + word[i+1:]\n                chain_len = max(chain_len, chainEndingAt(pred) + 1)\n            return chain_len\n        \n        ans = 0\n        for word in words:\n            ans = max(ans, chainEndingAt(word))\n        return ans\n        \n        '''\n        DP\n        dp function:\n        chain[word2] = max(chain[word1]+1 for all word1 if word1 is predecessor of word2)\n        '''\n        # dp = {}\n        # for w in sorted(words, key=len):\n        #     dp[w] = 1\n        #     for i in range(len(w)):\n        #         dp[w] = max(dp[w], dp.get(w[:i] + w[i+1:],0) + 1)\n        # return max(dp.values())\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        dp = {}\n        by_length = collections.defaultdict(set)\n        for w in words:\n            by_length[len(w)].add(w)\n        for i, l in enumerate(sorted(by_length.keys())):\n            if i == 0:\n                for w in by_length[l]:\n                    dp[w] = 1\n            else:\n                if not by_length[l - 1]:\n                    for w in by_length[l]:\n                        dp[w] = 1\n                else:\n                    for w in by_length[l]:\n                        dp[w] = 1\n                        for j in range(len(w)):\n                            candidate = w[:j] + w[j + 1:]\n                            if candidate in by_length[l - 1]:\n                                dp[w] = max(dp[w], dp[candidate] + 1)\n        return max(dp.values())", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n            d={j:1 for j in words}\n            n=len(words);used={};c=[0]\n            words=sorted(words,key=len)\n            def dfs(s,l):\n                if not s or s not in d:\n                    c[0]=max(c[0],len(l))\n                    return\n                used[s]=1\n                m=0\n                for i in range(len(s)):\n                     dfs(s[:i]+s[i+1:],l+[s])\n                     m=max(m,len(l))\n            for i in range(n-1,-1,-1):\n                if words[i] not in used and c[0]<i:\n                    dfs(words[i],[])\n            return c[0]\n                \n                \n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        def predecessor(word1, word2):\n            for i in range(len(word2)):\n                if word2[0:i] + word2[i + 1:] == word1:\n                    return True\n            return False\n        words.sort(key = len)\n        words_sort = {}\n        for i in words:\n            if len(i) in words_sort:\n                words_sort[len(i)].append(i)\n            else:\n                words_sort[len(i)] = [i]\n        mx = len(words_sort)\n        def dfs(words, words_sort):\n            max_chain = 1\n            stack = [(1, word) for word in words[::-1]]\n            while stack:\n                current = stack.pop()\n                if current[0] > max_chain:\n                    max_chain = current[0]\n                    if max_chain == mx:\n                        return max_chain\n                if len(current[1]) + 1 in words_sort:\n                    for word in words_sort[len(current[1]) + 1]:\n                        if predecessor(current[1], word):\n                            if (1, word) in stack:\n                                stack.remove((1, word))\n                            stack.append((current[0] + 1, word))\n                else:\n                    continue\n            return max_chain\n        max_chain = dfs(words, words_sort)\n        return max_chain\n", "class Solution:\n    def differ(self,x1,x2):\n        i,j =0,0\n        diff=0\n        while i!=len(x1) and j!=len(x2):\n            if x1[i]!=x2[j]:\n                diff+=1\n            else:\n                i+=1\n            if diff>1:\n                return False\n            j+=1\n        return True\n    \n    def check(self,x1,x2):\n        if x1==x2:\n            return True\n        \n        if abs(len(x1)-len(x2))!=1:\n            return False\n        else:\n            if len(x2)>len(x1):\n                a,b = x1,x2\n            else:\n                a,b = x2,x1\n            return self.differ(a,b)\n    \n    def longestStrChain(self, words: List[str]) -> int:\n        words = list(set(words))\n        lengths = {}\n        for word in words:\n            length = len(word)\n            lengths[length] = lengths.get(length,[])+[word]\n        \n        lengths = sorted(lengths.items(),key = lambda x :x[0],reverse=True)\n        value = {}\n        max_chain = 1\n        for i,length in enumerate(lengths):\n            for word in length[1]:\n                if i ==0:\n                    value[word]=1\n                else:\n                    temp_max = 0\n                    for temp_word in lengths[i-1][1]:\n                        if self.check(word,temp_word):\n                            temp_max = max(temp_max,value[temp_word])\n                \n                    value[word] = 1+temp_max\n                    max_chain = max(value[word],max_chain)\n        \n        return max_chain", "class Solution:\n    def helper(self, memo, s, w):\n        if w in memo: return memo[w]\n        count = 0\n        for i in range(len(w)):\n            pre = w[:i] + w[i+1:]\n            if pre in s:\n                count = max(count, self.helper(memo, s, pre))\n        memo[w] = 1 + count\n        return 1 + count\n\n    def longestStrChain(self, words: List[str]) -> int:\n        ans = 0\n        memo = {}\n        for w in words:\n            ans = max(ans, self.helper(memo, set(words), w))\n        return ans", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        sets = collections.defaultdict(set)\n        n, dp = 0, {}\n        for word in words:\n            n = max(n, len(word))\n            sets[len(word)].add(word)\n            dp[word] = 1\n        \n        ans = 1\n        for i in reversed(list(range(2, n+1))):\n            if i-1 not in sets:\n                continue\n            \n            for word in sets[i]:\n                for j in range(len(word)):\n                    new_word = word[:j] + word[j+1:]\n                    if new_word in sets[i-1]:\n                        dp[new_word] = dp[word] + 1\n                        ans = max(ans, dp[new_word])\n        \n        return ans\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        counter = collections.defaultdict(int)\n        longest = 0\n        \n        for w in sorted(words, key=len):\n            for i in range(len(w)):\n                subword = w[:i] + w[i+1:]\n                count = counter[subword] + 1\n                counter[w] = max(counter[w], count)\n                longest = max(longest, counter[w])\n        \n        return longest", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        words.sort(key=len)\n        dp = [1 for _ in range(len(words))]\n        start = collections.defaultdict(int)\n        end = collections.defaultdict(int)\n        \n        for i in range(len(words)-1, -1, -1):\n            start[(len(words[i]))] = i\n            \n        if len(start) == 1:\n            return 1\n            \n        for i in range(len(words)):\n            end[(len(words[i]))] = i\n            \n        res = 1\n            \n        for i in range(start[len(words[0])+1], len(words)):\n            for j in range(start[len(words[i])-1], end[len(words[i])-1]+1):\n                charA = set(words[j])\n                charB = set(words[i])\n                intersect = len(charA.intersection(charB))\n                if intersect == len(charA):\n                    dp[i] = max(dp[i], dp[j]+1)\n            res = max(res, dp[i])\n\n        return res\n", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        if not words:\n            return 0\n        \n        # bucket sort -> map len to words\n        len2words = defaultdict(list)\n        for w in words:\n            len2words[len(w)].append(w)\n        \n        # build graph out of all pairs of words\n        graph = defaultdict(list)\n        in_degrees = defaultdict(int)\n        for w1 in words:\n            for w2 in len2words[len(w1)-1]:\n                if self.isPredecessor(w1, w2):\n                    # w1 have more words -> w2->w1\n                    graph[w2].append(w1)\n                    in_degrees[w1] += 1\n        \n        max_len = 1\n        # topological sort to get the maximum length ending with each word\n        queue = deque([(w, 1) for w in graph if in_degrees[w] == 0])\n        while queue:\n            word, path_len = queue.popleft()\n            for child in graph[word]:\n                in_degrees[child] -= 1\n                if in_degrees[child] == 0:\n                    queue.append((child, path_len + 1))\n            \n            max_len = path_len\n        return max_len\n        \n\n    def isPredecessor(self, w1, w2):\n        if len(w1) != len(w2) + 1:\n            return False\n        \n        i1 = 0\n        i2 = 0\n        added = False\n        while i1 < len(w1) and i2 < len(w2):\n            if w1[i1] != w2[i2] and added:\n                return False\n            elif w1[i1] != w2[i2]:\n                i1 += 1\n                added = True\n            else:\n                i1 += 1\n                i2 += 1\n\n        return True", "class Solution:\n    def longestStrChain(self, words: List[str]) -> int:\n        self.ans = 0\n        words = sorted(words, key=lambda x: len(x))\n        \n        self.n = len(words)\n        self.m = {}\n        for i in range(self.n):\n            if words[i] in self.m:\n                self.m[words[i]] = i\n            else:\n                self.m[words[i]] = i\n        for i in range(self.n - 1, -1, -1):\n            self.findLongest(words, i, 0)\n        return self.ans\n    \n    def findLongest(self, words, i, cur_ans):\n        for j in range(len(words[i])):\n            if words[i][:j] + words[i][j + 1:] in self.m:\n                self.findLongest(words, self.m[words[i][:j] + words[i][j + 1:]], cur_ans + 1)\n            \n        self.ans = max(self.ans, cur_ans + 1)"]