题目描述:
给定一个字符串牌照 licensePlate 和一个字符串数组 words ,请你找出并返回 words 中的 最短补全词 。
如果单词列表(words)中的一个单词包含牌照(licensePlate)中所有的字母,那么我们称之为 补全词 。在所有完整词中,最短的单词我们称之为 最短补全词 。
单词在匹配牌照中的字母时要:
- 忽略牌照中的数字和空格。
- 不区分大小写,比如牌照中的 “P” 依然可以匹配单词中的 “p” 字母。
- 如果某个字母在牌照中出现不止一次,那么该字母在补全词中的出现次数应当一致或者更多。
- 例如:licensePlate = “aBc 12c”,那么它由字母 ‘a’、‘b’ (忽略大写)和两个 ‘c’ 。可能的 补全词 是
“abccdef”、“caaacab” 以及 “cbca” 。
题目数据保证一定存在一个最短补全词。当有多个单词都符合最短补全词的匹配条件时取单词列表中最靠前的一个。
示例一:
输入:licensePlate = “1s3 PSt”, words = [“step”, “steps”, “stripe”, “stepple”]
输出:“steps”
说明:最短补全词应该包括 “s”、“p”、“s” 以及 “t”。在匹配过程中我们忽略牌照中的大小写。
“step” 包含 “t”、“p”,但只包含一个 “s”,所以它不符合条件。
“steps” 包含 “t”、“p” 和两个 “s”。
“stripe” 缺一个 “s”。
“stepple” 缺一个 “s”。
因此,“steps” 是唯一一个包含所有字母的单词,也是本样例的答案。
示例 2:
输入:licensePlate = “1s3 456”, words = [“looks”, “pest”, “stew”, “show”]
输出:“pest”
说明:存在 3 个包含字母 “s” 且有着最短长度的补全词,“pest”、“stew”、和 “show” 三者长度相同,但我们返回最先出现的补全词 “pest” 。
方法一:比较计数
算法:
- 我们计算 word 和 licenseplate 中的字母数,转换为小写并忽略非字母字符。如果单词中每个字母的计数大于或等于
licenseplate 中的字母数,则该单词是 licensePlate 的完整词。 - 我们需要选择最短的完整词且最先出现的单词。
class Solution {
public String shortestCompletingWord(String licensePlate, String[] words) {
int[] target = count(licensePlate);
String ans = "";
for (String word: words)
if ((word.length() < ans.length() || ans.length() == 0) &&
dominates(count(word.toLowerCase()), target))
ans = word;
return ans;
}
public boolean dominates(int[] count1, int[] count2) {
for (int i = 0; i < 26; ++i)
if (count1[i] < count2[i])
return false;
return true;
}
public int[] count(String word) {
int[] ans = new int[26];
for (char letter: word.toCharArray()){
int index = Character.toLowerCase(letter) - 'a';
if (0 <= index && index < 26)
ans[index]++;
}
return ans;
}
}
方法二:哈希
解题思路:
- 用长度为26的int[]数组作为哈希表,统一使用小写(大写字母转换为小写),记录每个字母出现的次数。
- 根据licensePlate构造好哈希表,再对words的每个单词进行检查。
- 若license所有字母包括个数(忽略字母以外的数字空格等字符)都匹配上,再判断单词长度,从而得到最短完整单词;若有多个最短完整词,输出最靠前的一个。
class Solution {
public String shortestCompletingWord(String licensePlate, String[] words) {
int[] hash = new int[26];
int[] temp = new int[26];//hash[]数组的拷贝,用于选取最短完整词
int cnt1 = 0;
String output = "";
int shortest = 16;//记录当前最短完整词的长度
char[] license = licensePlate.toCharArray();
for(char c : license)
{
if(c >= 'A' && c <= 'Z') c += 32;
if(c >= 'a' && c <= 'z')
{
hash[c - 'a']++;
cnt1++;
}
}
for(String w : words)
{
char[] word = w.toCharArray();
int len = word.length;
int cnt2 = cnt1;
for(int i = 0; i < 26; i++)
temp[i] = hash[i];
for(char c : word)
{
if(c >= 'A' && c <= 'Z') c += 32;
if(temp[c - 'a'] > 0)
{
temp[c - 'a']--;
cnt2--;
}
if(cnt2 == 0 && len < shortest)
{
shortest = len;
output = w;
break;
}
}
}
return output;
}
}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-completing-word