Info
Didn’t solve this problem bottom up, which would be faster.
- Worth thinking about a little bit and then checking the editorial for this.
TARGET DECK: Leetcode FILE TAGS: Medium
Intuition
- For every word, run DFS such that you remove every letter of that word one by one and see if it is in the words.
- If that word is in the words, then you know that you may go to the index + 1 (since you only removed 1 letter and so index + 1 exists), yet be careful here since there are multiple words with the same length (so index + 1 is not necessarily the predecessor with the letter chopped off).
- Therefore, you have to use .index() similar to Without Word Index, or otherwise use a word index: With Word Index.
- In the code, I did
words.sort(key = lambda x: -len(x))to sort in descending order of word length, so it would be index + 1 instead.
Cards
START
Basic
Front: Longest String Chain - LeetCode
Back: words.sort(key = lambda x: -len(x), making sure to index to the correct position since there are many words of the same length.
END
Complexity
Runtime
, where L is the length of the string, and we iterate through every character of every string within each recursion, and we run this DFS for every possible string in the outer for loop.
Space
to store the words and word index.
Code
DP Optimization
class Solution:
def longestStrChain(self, words: List[str]) -> int:
words.sort(key = lambda x: -len(x))
word_index = {}
for i, word in enumerate(words):
word_index[word] = i
dp = {}
n = len(words)
def r(i):
if i in dp:
return dp[i]
max_chain = 1
for j in range(len(words[i])):
pred = words[i][:j] + words[i][j+1:]
if pred in words:
max_chain = max(max_chain, 1 + r(word_index[pred]))
dp[i] = max_chain
return max_chain
max_chain = 0
for i in range(len(words)):
max_chain = max(max_chain, r(i))
return max_chain- This works since every word has a unique index (you are just going through every word in the list).
With Word Index
class Solution:
def longestStrChain(self, words: List[str]) -> int:
words.sort(key = lambda x: -len(x))
word_index = {}
for i, word in enumerate(words):
word_index[word] = i
dp = {}
n = len(words)
def r(i):
if words[i] in dp:
return dp[words[i]]
max_chain = 1
for j in range(len(words[i])):
pred = words[i][:j] + words[i][j+1:]
if pred in words:
max_chain = max(max_chain, 1 + r(word_index[pred]))
dp[words[i]] = max_chain
return max_chain
max_chain = 0
for i in range(len(words)):
max_chain = max(max_chain, r(i))
return max_chainWithout Word Index
class Solution:
def longestStrChain(self, words: List[str]) -> int:
words.sort(key = lambda x: -len(x))
dp = {}
n = len(words)
def r(i):
if words[i] in dp:
return dp[words[i]]
max_chain = 1
for j in range(len(words[i])):
pred = words[i][:j] + words[i][j+1:]
if pred in words:
max_chain = max(max_chain, 1 + r(words.index(pred)))
dp[words[i]] = max_chain
return max_chain
max_chain = 0
for i in range(len(words)):
max_chain = max(max_chain, r(i))
return max_chain