@(LeetCode)
问题描述
给定一个字符串数组 words
,找到 length(word[i]) * length(word[j])
的最大值,且要求两个字符串没有公共字符。假定每个字符串只包含小写字母。如果不存在这样的两个字符串,则返回 0
。
栗 1:
输入: ["abcw","baz","foo","bar","xtfn","abcdef"]
输出: 16
解释:
两个单词为:"abcw", "xtfn"
栗 2:
输入: ["a","ab","abc","d","cd","bcd","abcd"]
输出: 4
解释:
两个单词为:"ab", "cd"
栗 3:
输入: ["a","aa","aaa","aaaa"]
输出: 0
解释:
不存在这样的字符串
解题思路
常规思路
以常规思路来解,还是挺简单的。
遍历所有可能的字符串组合,对比两个字符串是否存在相同字符即可。
但这种方式效率不太高,因为需要每次都要比较是否存在相同的字符。
位操作
一种比较巧妙的思路,利用二进制位操作,非常简单的计算出字符串是否有相同的字符。
因为字符串全是小写字母,所以字符集最多为 26
个,完全可以用 26
位二进制来表示出现过的字符。
主要思路如下:
- 用
26
位二进制表示出现过的字符,在字符对应的位上填1
,其他填0
。 - 两个二进制数进行
与运算
,如果为0
,则表示无公共字符。
下面来具体解释一下。
-
假设有
26
个空位,分别对照a~z
。将字符串中出现的字符,在对应的位置上填上1
,未出现的默认填0
,那么可以得到一串1/0
组成的数字,可将其看做一组二进制位。比如
abc
可表示为:a b c d e f g h i j k l m n o p q r s t u v w x y z 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
baz
:11000000000000000000000001
foo
:00000100000000100000000000
-
如果两个字符串没有公共字符,与运算肯定为
0
。为了方便理解,这里的栗子,
a
是在最高位。在进行位计算时,需要将1
左移25 - (ch - 'a')
后,再与原值相或,得到的整数就是该字符串的位表示,存入数组即可。比如a
,需要将1
左移25
位,才能在最高位填上1
;同理,b
左移24
位。
二进制数计算如下:
i = 0
while (i < words.length) {
const word = words[i]
let val = 0
let j = 0
while (j < word.length) {
const ch = word[j]
const dis = ch.charCodeAt() - 'a'.charCodeAt()
// 将字符对应的位置填上 1
val |= 1 << (25 - dis)
j += 1
}
mask[i] = val
i += 1
}
判断是否有相同字符:
i = 0
while (i < words.length - 1) {
const word1 = words[i]
let j = i + 1
while (j < words.length) {
const word2 = words[j]
// 按位与,不存在相同字符,注意加括号
if ((mask[i] & mask[j]) === 0) {
const product = word1.length * word2.length
if (product > maxLen) {
maxLen = product
}
}
j += 1
}
i += 1
}
网友评论