Longest String Chain
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ words.length ≤ 8 - ◆
1 ≤ words[i].length ≤ 8 - ◆
words[i] consists of lowercase English letters - ◆
All the strings in words are distinct
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Recursive Without Memoization
BruteA word can only ever follow a predecessor formed by deleting exactly one of its own letters — inserting one letter into the predecessor recovers the word, keeping every other letter's order intact. So for any word, the longest chain ending there is 1 plus the best chain achievable by whichever single-letter deletion also happens to be present in the given list — or just 1, if none of its deletions are present at all. Trying every word as the potential end of the chain and recursively chasing each one back through its usable deletions finds the answer, but the same shorter word gets re-explored from scratch every time a different longer word deletes down to it.
O(n · 2^L)O(L)1class Solution {
2 private Set<String> wordSet;
3
4 public int longestStrChain(String[] words) {
5 wordSet = new HashSet<>(Arrays.asList(words));
6 int best = 1;
7 for (String w : words) {
8 best = Math.max(best, solve(w));
9 }
10 return best;
11 }
12
13 private int solve(String word) {
14 int best = 1;
15 for (int i = 0; i < word.length(); i++) {
16 String pred = word.substring(0, i) + word.substring(i + 1);
17 if (wordSet.contains(pred)) {
18 best = Math.max(best, 1 + solve(pred));
19 }
20 }
21 return best;
22 }
23}Optimal — Bottom-Up DP with a HashMap
OptimalSort the words shortest to longest, since every predecessor of a word is exactly one letter shorter and therefore must be processed earlier in that order. Let dp[word] hold the length of the longest chain that ends at word. For each word in sorted order, try every single-letter deletion of it; whenever that shorter string is a key already sitting in dp (meaning it's both one of the given words and already been processed), dp[word] can extend it by one. Recording each word's result the moment it's computed means later, longer words can just look their predecessors up in O(1) instead of re-deriving them.
O(n · L)O(n · L)1class Solution {
2 public int longestStrChain(String[] words) {
3 String[] sorted = words.clone();
4 Arrays.sort(sorted, (a, b) -> a.length() - b.length());
5 Map<String, Integer> dp = new HashMap<>();
6 int best = 1;
7 for (String w : sorted) {
8 int cur = 1;
9 for (int i = 0; i < w.length(); i++) {
10 String pred = w.substring(0, i) + w.substring(i + 1);
11 if (dp.containsKey(pred)) {
12 cur = Math.max(cur, dp.get(pred) + 1);
13 }
14 }
15 dp.put(w, cur);
16 best = Math.max(best, cur);
17 }
18 return best;
19 }
20}