Longest Word in Dictionary through Deleting
Longest Word in Dictionary Through Deleting Problem
Problem
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.
Examples
Example 1:
Input:
s = "abpcplea", dictionary = ["ale","apple","monkey","plea"]
Output:
"apple"
Example 2:
Input:
s = "abpcplea", dictionary = ["a","b","c"]
Output:
"a"
Solution
Method 1 – Two Pointers and Subsequence Check
Intuition
The main idea is to check for each word in the dictionary if it is a subsequence of the given string. If multiple words are valid, we return the longest one, and if there is a tie, the lexicographically smallest one.
Approach
- Iterate through each word in the dictionary.
- For each word, use two pointers to check if it is a subsequence of the given string.
- Track the longest valid word found so far. If two words have the same length, choose the lexicographically smaller one.
- Return the answer after checking all words.
Code
C++
class Solution {
public:
string findLongestWord(string s, vector<string>& d) {
string ans = "";
for (auto& w : d) {
int i = 0, j = 0;
while (i < s.size() && j < w.size()) {
if (s[i] == w[j]) j++;
i++;
}
if (j == w.size()) {
if (w.size() > ans.size() || (w.size() == ans.size() && w < ans)) ans = w;
}
}
return ans;
}
};
Go
func findLongestWord(s string, d []string) string {
ans := ""
for _, w := range d {
i, j := 0, 0
for i < len(s) && j < len(w) {
if s[i] == w[j] {
j++
}
i++
}
if j == len(w) {
if len(w) > len(ans) || (len(w) == len(ans) && w < ans) {
ans = w
}
}
}
return ans
}
Java
class Solution {
public String findLongestWord(String s, List<String> d) {
String ans = "";
for (String w : d) {
int i = 0, j = 0;
while (i < s.length() && j < w.length()) {
if (s.charAt(i) == w.charAt(j)) j++;
i++;
}
if (j == w.length()) {
if (w.length() > ans.length() || (w.length() == ans.length() && w.compareTo(ans) < 0)) ans = w;
}
}
return ans;
}
}
Kotlin
class Solution {
fun findLongestWord(s: String, d: List<String>): String {
var ans = ""
for (w in d) {
var i = 0; var j = 0
while (i < s.length && j < w.length) {
if (s[i] == w[j]) j++
i++
}
if (j == w.length) {
if (w.length > ans.length || (w.length == ans.length && w < ans)) ans = w
}
}
return ans
}
}
Python
class Solution:
def findLongestWord(self, s: str, d: list[str]) -> str:
ans = ""
for w in d:
i = j = 0
while i < len(s) and j < len(w):
if s[i] == w[j]:
j += 1
i += 1
if j == len(w):
if len(w) > len(ans) or (len(w) == len(ans) and w < ans):
ans = w
return ans
Rust
impl Solution {
pub fn find_longest_word(s: String, d: Vec<String>) -> String {
let mut ans = String::new();
for w in d.iter() {
let (mut i, mut j) = (0, 0);
let s_bytes = s.as_bytes();
let w_bytes = w.as_bytes();
while i < s_bytes.len() && j < w_bytes.len() {
if s_bytes[i] == w_bytes[j] { j += 1; }
i += 1;
}
if j == w_bytes.len() {
if w.len() > ans.len() || (w.len() == ans.len() && w < &ans) {
ans = w.clone();
}
}
}
ans
}
}
TypeScript
class Solution {
findLongestWord(s: string, d: string[]): string {
let ans = "";
for (const w of d) {
let i = 0, j = 0;
while (i < s.length && j < w.length) {
if (s[i] === w[j]) j++;
i++;
}
if (j === w.length) {
if (w.length > ans.length || (w.length === ans.length && w < ans)) ans = w;
}
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n * m), wherenis the number of words in the dictionary andmis the length of the strings, since for each word we may scan all ofs. - 🧺 Space complexity:
O(1), as only a few variables are used for tracking the answer.
Method 2 – Sorting and Subsequence Check
Intuition
By sorting the dictionary by length (descending) and lexicographically (ascending), we can return the first word that is a subsequence of the given string, which guarantees the correct answer.
Approach
- Sort the dictionary by length (descending) and lexicographically (ascending).
- For each word, check if it is a subsequence of the given string using two pointers.
- Return the first valid word found.
Code
C++
class Solution {
public:
string findLongestWord(string s, vector<string>& d) {
sort(d.begin(), d.end(), [](const string& a, const string& b) {
return a.size() > b.size() || (a.size() == b.size() && a < b);
});
for (auto& w : d) {
int i = 0, j = 0;
while (i < s.size() && j < w.size()) {
if (s[i] == w[j]) j++;
i++;
}
if (j == w.size()) return w;
}
return "";
}
};
Go
import "sort"
func findLongestWord(s string, d []string) string {
sort.Slice(d, func(i, j int) bool {
if len(d[i]) != len(d[j]) {
return len(d[i]) > len(d[j])
}
return d[i] < d[j]
})
for _, w := range d {
i, j := 0, 0
for i < len(s) && j < len(w) {
if s[i] == w[j] {
j++
}
i++
}
if j == len(w) {
return w
}
}
return ""
}
Java
class Solution {
public String findLongestWord(String s, List<String> d) {
d.sort((a, b) -> b.length() != a.length() ? b.length() - a.length() : a.compareTo(b));
for (String w : d) {
int i = 0, j = 0;
while (i < s.length() && j < w.length()) {
if (s.charAt(i) == w.charAt(j)) j++;
i++;
}
if (j == w.length()) return w;
}
return "";
}
}
Kotlin
class Solution {
fun findLongestWord(s: String, d: List<String>): String {
val sorted = d.sortedWith(compareByDescending<String> { it.length }.thenBy { it })
for (w in sorted) {
var i = 0; var j = 0
while (i < s.length && j < w.length) {
if (s[i] == w[j]) j++
i++
}
if (j == w.length) return w
}
return ""
}
}
Python
class Solution:
def findLongestWord(self, s: str, d: list[str]) -> str:
d.sort(key=lambda x: (-len(x), x))
for w in d:
i = j = 0
while i < len(s) and j < len(w):
if s[i] == w[j]:
j += 1
i += 1
if j == len(w):
return w
return ""
Rust
impl Solution {
pub fn find_longest_word(s: String, mut d: Vec<String>) -> String {
d.sort_by(|a, b| b.len().cmp(&a.len()).then(a.cmp(b)));
for w in d.iter() {
let (mut i, mut j) = (0, 0);
let s_bytes = s.as_bytes();
let w_bytes = w.as_bytes();
while i < s_bytes.len() && j < w_bytes.len() {
if s_bytes[i] == w_bytes[j] { j += 1; }
i += 1;
}
if j == w_bytes.len() {
return w.clone();
}
}
String::new()
}
}
TypeScript
class Solution {
findLongestWord(s: string, d: string[]): string {
d.sort((a, b) => b.length - a.length || a.localeCompare(b));
for (const w of d) {
let i = 0, j = 0;
while (i < s.length && j < w.length) {
if (s[i] === w[j]) j++;
i++;
}
if (j === w.length) return w;
}
return "";
}
}
Complexity
- ⏰ Time complexity:
O(n * m + n log n), wherenis the number of words in the dictionary andmis the length of the strings, due to sorting and checking subsequences. - 🧺 Space complexity:
O(n), for sorting the dictionary.