题目
leetcode题目:(链接https://leetcode-cn.com/problems/find-words-that-can-be-formed-by-characters/)。
给你一份『词汇表』(字符串数组)words和一张『字母表』(字符串)chars。
假如你可以用 chars 中的『字母』(字符)拼写出words中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。
注意:每次拼写时,chars中的每个字母都只能用一次。
返回词汇表words中你掌握的所有单词的长度之和。
示例 1:
输入:words = ["cat","bt","hat","tree"], chars = "atach"
输出:6
解释:
可以形成字符串 "cat" 和 "hat",所以答案是 3 + 3 = 6。
示例 1:
输入:words = ["hello","world","leetcode"], chars = "welldonehoneyr"
输出:10
解释:
可以形成字符串 "hello" 和 "world",所以答案是 5 + 5 = 10。
基本思路
我一开始想到的是遍历words里每个字符串,对于每一个words[i]里的字母,在chars里找对应字母并删除同时记数,在遍历完每一个words[i]后比较计数器和words[i]的大小关系,若想等则在最终结果上加上计数器的值。这个方法可行,但是涉及字符串的改变,运算时间太长了。
涉及要记录多个值各自的数量的时候,我们可以考虑用哈希表,键值对可以很方便地记录信息。本题中我们可以用一个哈希表Map1记录每个words[i]里的每个字母的数量,用另一个哈希表Map2记录chars里每个字母的数量,然后进行比较,只要Map1里每个key所对应的value都小于等于Map2中同样的key所对应的value的值,就认为可以拼出来这个单词。
使用真正的哈希表时,存储涉及了哈希运算,也在消耗时间。对于这种可以确定数量的题目,我们可以用数组来完成哈希表的功能。我们可以使用一个长度为26的数组 w 来表示 words[i] 中每个字母的数量,使用长度为26的数组 c 来表示 chars 中每个字母的数量,比较 w 和 c 相同位置的大小即可。
后续优化:进行值的比较耗费时间过长,我们可以考虑去掉上述的数组 w,遍历 words[i] 中每个字母时,将 c 中对应字母数量减一,若出现负数则判定为不可。
具体代码
最初想法——字符串裁剪:
//Java
class Solution {
public int countCharacters(String[] words, String chars) {
StringBuilder sb;
int ans = 0;
for(int i = 0; i < words.length; i++) {
sb = new StringBuilder(chars);
int count = 0;
for(int j = 0; j < words[i].length(); j++) {
int index = sb.indexOf(String.valueOf(words[i].charAt(j)));
if(index > -1) {
sb.deleteCharAt(index);
count++;
}
}
if(count == words[i].length()) {
ans = ans + count;
}
}
return ans;
}
}
时间复杂度:遍历了words[]中的所有字母,所以时间复杂度为
O
(
n
)
O(n)
O(n),n表示words[]中所有字母数量总和。
空间复杂度:额外需要m个空间存放StringBuilder,空间复杂度为
O
(
m
)
O(m)
O(m),m表示words[]中字符串的数量。
哈希数组——优化后:
//Java
class Solution {
public int countCharacters(String[] words, String chars) {
int[] c = new int[26];
Arrays.fill(c, 0);
int ans = 0;
for(int i = 0; i < chars.length(); i++) {
c[chars.charAt(i) - 97]++;
}
for(int i = 0; i < words.length; i++) {
if(needAdd(words[i], c)) {
ans = ans + words[i].length();
}
}
return ans;
}
private boolean needAdd(String w, int[] c) {
int[] temp = new int[c.length];
System.arraycopy(c, 0, temp, 0, c.length);
for(int i = 0; i < w.length(); i++) {
if(--temp[w.charAt(i) - 97] < 0) {
return false;
}
}
return true;
}
}
时间复杂度:遍历了words[]中的所有字母,所以时间复杂度为
O
(
n
)
O(n)
O(n),n表示words[]中所有字母数量总和。
空间复杂度:对于这种调用方法后进行变量声明的模块,空间复杂度如何计算,博主没有查到相关的例子,希望有经验的小伙伴可以给与帮助。