统计追加字母可以获得的单词数
题目地址: https://leetcode-cn.com/problems/count-words-obtained-after-adding-a-letter/
题目描述
给你两个下标从 0 开始的字符串数组 startWords
和 targetWords
。每个字符串都仅由 小写英文字母 组成。
对于 targetWords
中的每个字符串,检查是否能够从 startWords
中选出一个字符串,执行一次 转换操作 ,得到的结果与当前 targetWords
字符串相等。
转换操作 如下面两步所述:
- 追加任何不存在于当前字符串的任一小写字母到当前字符串的末尾。
- 例如,如果字符串为
"abc"
,那么字母'd'
、'e'
或'y'
都可以加到该字符串末尾,但'a'
就不行。如果追加的是'd'
,那么结果字符串为"abcd"
。
- 例如,如果字符串为
- 重排新字符串中的字母,可以按任意顺序重新排布字母。
- 例如,
"abcd"
可以重排为"acbd"
、"bacd"
、"cbda"
,以此类推。注意,它也可以重排为"abcd"
自身。
- 例如,
找出 targetWords
中有多少字符串能够由 startWords
中的 任一 字符串执行上述转换操作获得。返回 targetWords
中这类 字符串的数目 。
**注意:**你仅能验证 targetWords
中的字符串是否可以由 startWords
中的某个字符串经执行操作获得。startWords
中的字符串在这一过程中 不 发生实际变更。
示例 1:
输入:startWords = ["ant","act","tack"], targetWords = ["tack","act","acti"]
输出:2
解释:
- 为了形成 targetWords[0] = "tack" ,可以选用 startWords[1] = "act" ,追加字母 'k' ,并重排 "actk" 为 "tack" 。
- startWords 中不存在可以用于获得 targetWords[1] = "act" 的字符串。
注意 "act" 确实存在于 startWords ,但是 必须 在重排前给这个字符串追加一个字母。
- 为了形成 targetWords[2] = "acti" ,可以选用 startWords[1] = "act" ,追加字母 'i' ,并重排 "acti" 为 "acti" 自身。
示例 2:
输入:startWords = ["ab","a"], targetWords = ["abc","abcd"]
输出:1
解释:
- 为了形成 targetWords[0] = "abc" ,可以选用 startWords[0] = "ab" ,追加字母 'c' ,并重排为 "abc" 。
- startWords 中不存在可以用于获得 targetWords[1] = "abcd" 的字符串。
提示:
1 <= startWords.length, targetWords.length <= 5 * 104
1 <= startWords[i].length, targetWords[j].length <= 26
startWords
和targetWords
中的每个字符串都仅由小写英文字母组成- 在
startWords
或targetWords
的任一字符串中,每个字母至多出现一次
思路:
字符串的提示范围中有一条 在 startWords
或 targetWords
的任一字符串中,每个字母至多出现一次。那么熟悉位运算的就会有如下思路
- 字符数组
a
-z
一共有26位,一个int是32位 那么是不是可以用int来代替string- 比如
abc
那么对应就是int 32位中第0位,第1位,第1位为1,即转化为二进制就是 0111也就是数字7 - 长度相同字符串不同的字符对应的数字是不同,因为他们在int中1的位置不同,
- 长度相同字符串仅仅顺序不同对应的数字相同,也就是说
abc
和bac
对应的数字是一样的
- 比如
- 转换操作中,第一个操作就是新增一个字符,比如
abc
->abcd
,那么怎么通过数位转换来通过abcd
找到abc
abc
转化为二进制是000000111
,abcd
转化为二进制是00001111
, 那么很容易得到abc
^abcd
=00000111
^00001111
即00001000
, 那么就是在二进制中判断一个数是否只有一位为1,- 在二进制运算中有一种比较简单的方案即
a
&a-1
如果得0,那么代表这个数字的二进制只有一位为1. - 那么我们如果要获取一个二进制数,某一个数为1,那么就可以想到
a
& (-a
),比如 二进制运算中a
=00001100
,那么a
&-a
则为二进制最后一个1 即为00001000
, abcd
去掉每一位,那么总有abc这个选项
- 既然是需要从
target
中找start
,要尽可能快,那么只需要将start转化为可快速索引的数据结构,用Hashset
代码
将字符串转化为数字,我们需要将a映射为0,b映射为1,那么转换部分代码可以写为
public int turnToInt(String str){
int a = 0;
for(int i = 0; i < str.length(); i++){
a |= 1 << (str.charAt(i) - 'a');
}
return a;
}
那么最后的代码
public int wordCount(String[] startWords, String[] targetWords) {
HashSet<Integer> set = new HashSet(startWords.length);
for (String startWord : startWords) {
set.add(turnToInt(startWord));
}
int count = 0;
for (String targetWord : targetWords) {
if(targetWord.length() == 1){
continue;
}
int i = turnToInt(targetWord);
int tem = i;
while (tem != 0){
int index = tem & (-tem);
tem ^= index;
if(set.contains(i ^ index)){
count++;
break;
}
}
}
return count;
}
public int turnToInt(String str){
int a = 0;
for(int i = 0; i < str.length(); i++){
a |= 1 << (str.charAt(i) - 'a');
}
return a;
}
结果: