题目
给你一个字符串 s 和一个字符串数组 dictionary 作为字典,找出并返回字典中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。
如果答案不止一个,返回长度最长且字典序最小的字符串。如果答案不存在,则返回空字符串。
示例 1:
1 2
| 输入:s = "abpcplea", dictionary = ["ale","apple","monkey","plea"] 输出:"apple"
|
示例 2:
1 2
| 输入:s = "abpcplea", dictionary = ["a","b","c"] 输出:"a"
|
提示:
- 1 <= s.length <= 1000
- 1 <= dictionary.length <= 1000
- 1 <= dictionary[i].length <= 1000
- s 和 dictionary[i] 仅由小写英文字母组成
方法一:排序+双指针
比较直接简单的思路,就是利用自定义sort函数,满足最长、字典序最小的要求,再用双指针遍历每一个单词,得到的第一个解就是该题目的解。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Solution { public: string findLongestWord(string s, vector<string>& dictionary) { int n = dictionary.size(); sort(dictionary.begin(),dictionary.end(),[&](string s1,string s2){ if(s1.size()!=s2.size()){ return s1.size()>s2.size(); }else{ return s1<s2; } }); string ans; for(auto & word : dictionary){ int i=0,j=0; while(i<s.size() && j<word.size()){ if(word[j]==s[i]){ i++; j++; }else{ i++; } } if(j==word.size()){ ans = word; break; } } return ans; } };
|
方法二: 双指针+维护最优解
一个贪心思路:当s中存在两个相同字符和词典中的单词匹配时,优先选择匹配靠前的字符。
该方法较方法一时间复杂度高
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Solution { public: string findLongestWord(string s, vector<string>& dictionary) { int n = dictionary.size(); string ans; for(auto & word : dictionary){ int i=0,j=0; while(i<s.size() && j<word.size()){ if(word[j]==s[i]){ i++; j++; }else{ i++; } } if(j==word.size()){ if(word.size()>ans.size() || (word.size()==ans.size()&& word<ans)) ans = word; } } return ans; } };
|
方法三:动态规划
针对方法2进行改进,使用DP数组,对双指针遍历部分进行简化。
DP数组虽然是二维,但是一层的长度只要涵盖26个英文字母就好。状态转移方程为:
其含义是,对于s中的第$i$个位置,字符j将会在$dp[i][j]$处出现,所以显然当$s[i]=j$时,出现为$i$,否则就看看$i+1$是否知道位置。
因此该DP数组要倒退实现。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class Solution { public: string findLongestWord(string s, vector<string>& dictionary) { int n = s.size(); vector<vector<int>> dp(n+1,vector<int>(26,n)); for(int i=n-1;i>=0;i--){ for(int j=0;j<26;j++){ if('a'+j==s[i]){ dp[i][j]=i; }else{ dp[i][j] = dp[i+1][j]; } } } string ans=""; for(auto & word : dictionary){ bool match=true; int i=0; for(auto & c : word){ if(dp[i][c-'a']==n){ match=false; break; }else{ i = dp[i][c-'a']+1; } }
if(match){ if(word.size()>ans.size() || (word.size()==ans.size()&& word<ans)) ans = word; } } return ans; } };
|
原文链接: https://zijian.wang/2021/09/13/524. 通过删除字母匹配到字典里最长单词(排序 双指针 二维DP)/
版权声明: 转载请注明出处.