题目
给你两个下标从 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" 自身。
前言
实话讲,读题花了10分钟;大神们4题做完才花了14分钟;语文不好,影响学习。囧
题解
暴力求解
- 所有的新字符串只能从startWords生成
- 那就先根据startWords数组,枚举所有生成新字符串的可能;
- 比如startWords=['a'],必然可以生成['ab','ac','ad',...,'ay','az']
- 将根据比如startWords生成的字符串根据ascii码排序放入哈希表map中
- 枚举targetWords中字符串,如果targetWords中字符串可以再map中找到,数量+1
- 返回结果
暴力求解代码
var wordCount = function (startWords, targetWords) {
let map = {}
startWords.forEach((k) => {
const list = k.split('')
for (let i = 0; i < 26; i++) {
const s = String.fromCharCode(97 + i)
if (!list.includes(s)) {
const t = list.concat([s])
const k = t.sort().join('')
map[k] = 1
}
}
})
let result = 0
targetWords.forEach((v) => {
const s = v.split('').sort().join('')
if (map[s] > 0) result++
})
return result
}
状态压缩
上一个思路是从startWords生成全部的可能的字符串,这个思路是从targetWords,枚举targetWords中字符串v,减少字符串任意1个字符,查看startWords是否存在,如果存在,该字符串v可以被转换
如何才能快速的实现上述操作呢;
假设startWords = ['ac', 'a'],targetWords = ['acd', 'ab', 'a'] ;
遍历startWords将字符串放入哈希表map中,map = {'ac','a'}
枚举targetWords,得到字符串'acd', 'ab', 'a';
对于'acd',可以由'cd'+'a'、'ad'+'c'、'ac'+'d';得到;在'ac'+'d'这个解中'ac'明显可以从map中查到,所以acd可以被startWords的字符串转换;
根据上述思路转编辑代码如下
代码
var wordCount = function (startWords, targetWords) {
const set = new Set()
const getIndex = (s) => s.charCodeAt() - 'a'.charCodeAt()
startWords.forEach((word) => {
let num = 0
for (let i = 0; i < word.length; i++) {
num |= 1 << getIndex(word[i])
}
set.add(num)
})
console.log('set', set)
// a b d
// a b c d
let result = 0
for (const target of targetWords) {
let x = 0
for (let i = 0; i < target.length; i++) {
x |= 1 << getIndex(target[i])
}
for (let i = 0; i < target.length; i++) {
let t = 1 << getIndex(target[i])
const k = x ^ t
if (set.has(k)) {
result++
break
}
}
}
return result
}