Longest Word in Dictionary through Deleting
MedPrompt
Given a string s and a string array dictionary, return the longest string in the dictionary that can be formed by deleting some of the given string characters. If there is more than one possible result, return the longest word with the smallest lexicographical order. If there is no possible result, return the empty string.
Example 1:
Input: s = "abpcplea", dictionary = ["ale","apple","monkey","plea"]
Output: "apple"Example 2:
Input: s = "abpcplea", dictionary = ["a","b","c"]
Output: "a"
Constraints:
1 <= s.length <= 10001 <= dictionary.length <= 10001 <= dictionary[i].length <= 1000sanddictionary[i]consist of lowercase English letters.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach simplifies the selection logic by pre-processing the dictionary. The idea is to sort the dictionary based on the desired criteria: first by decreasing word length, and then by increasing lexicographical order for words of the same length. After sorting, we iterate through the dictionary and the very first word that is a subsequence of the input string s will be the correct answer. This is because any subsequent word will either be shorter or lexicographically larger, thus not a better candidate.
Algorithm
- Create a custom comparator to sort strings. The comparator should first compare by length in descending order. If lengths are equal, it should compare lexicographically in ascending order. - Sort the
dictionarylist using this custom comparator. - Iterate through the now-sorteddictionary. - For eachwordin the dictionary, check if it is a subsequence ofsusing a helper functionisSubsequence. - TheisSubsequencefunction uses a two-pointer technique. One pointeriforsand anotherjforword. Traverses. Ifs.charAt(i)matchesword.charAt(j), incrementj. Always incrementi. The word is a subsequence ifjreaches the end of the word. - Since the dictionary is sorted by our desired criteria, the first word found to be a subsequence is the answer. Return it immediately. - If the loop finishes without finding any such word, return an empty string.
Walkthrough
The core idea is to sort the dictionary first so that the first valid word we encounter is guaranteed to be the answer. By sorting by length descending and then lexicographically ascending, we ensure that we check the best possible candidates first. Once a match is found, we can stop searching. ```java import java.util.Collections; import java.util.List;
class Solution { public String findLongestWord(String s, List<String> dictionary) { // Sort the dictionary: longest word first, then lexicographically smallest Collections.sort(dictionary, (a, b) -> { if (a.length() != b.length()) { return b.length() - a.length(); } return a.compareTo(b); });
for (String word : dictionary) { if (isSubsequence(s, word)) { return word; } } return "";} // Helper function to check if word is a subsequence of sprivate boolean isSubsequence(String s, String word) { int i = 0; // pointer for s int j = 0; // pointer for word while (i < s.length() && j < word.length()) { if (s.charAt(i) == word.charAt(j)) { j++; } i++; } return j == word.length();}}
Complexity
Time
O(m log m * l + m * n), where `m` is the number of words in the dictionary, `n` is the length of `s`, and `l` is the average length of words in the dictionary. The sorting step takes `O(m log m * l)` due to string comparisons. The iteration and subsequence check takes `O(m * n)` in the worst case. The sorting cost often dominates.
Space
O(log m) or O(m) for sorting. In Java, `Collections.sort` for lists uses Timsort which has an auxiliary space complexity of `O(log m)` on average and `O(m)` in the worst case.
Trade-offs
Pros
The logic after sorting is very clean and simple: find the first match and return.
Reduces complex conditional checks inside the loop.
Cons
The initial sorting step can be computationally expensive, especially for a large dictionary.
The overall time complexity is generally worse than the linear scan approach.
Solutions
Solution
class Solution {public String findLongestWord(String s, List<String> dictionary) { String ans = ""; for (String a : dictionary) { if (check(s, a) && (ans.length() < a.length() || (ans.length() == a.length() && a.compareTo(ans) < 0))) { ans = a; } } return ans; }private boolean check(String a, String b) { int m = a.length(), n = b.length(); int i = 0, j = 0; while (i < m && j < n) { if (a.charAt(i) == b.charAt(j)) { ++j; } ++i; } return j == n; }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.