题目描述
给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短。请问,如何最快地判断字符串B中所有字母是否都在字符串A里?
为了简单起见,我们规定输入的字符串只包含大写英文字母,请实现函数bool StringContains(string &A, string &B)
比如,如果是下面两个字符串:
String 1:ABCD
String 2:BAD
答案是true,即String2里的字母在String1里也都有,或者说String2是String1的真子集。
如果是下面两个字符串:
String 1:ABCD
String 2:BCE
答案是false,因为字符串String2里的E字母不在字符串String1里。
同时,如果string1:ABCD,string 2:AA,同样返回true。
分析与解法
哈希查表法:
首先考虑基于 String 1 构造一个 Hash 结构,然后遍历 String 2,检查每个字符是否都在 Hash 中
又因为字母是有限的(26个英文字母),因此该 Hash 结构的大小是有限的,因此可以用一个整数(32位即可)的从低位到高位的每一位代表一个字符,例如最低位代表 ‘A’,第 26 位代表 ‘Z’,每一位为 1 时代表字母存在,为 0 代表不存在
通过整数的 & 运算就可以判断 Hash 结构中是否存在某个字母
举个例子:
ABCD 转为整数的二进制表示就为:00000000000000000000001111
BCE,先看 B,转为二进制:00000000000000000000000010
00000000000000000000000010 & 00000000000000000000001111 != 0
继续判断 C,转为二进制:00000000000000000000000100
00000000000000000000000100 & 00000000000000000000001111 != 0
继续判断 E,转为二进制:00000000000000000000010000
00000000000000000000010000 & 00000000000000000000001111 == 0
当出现按位与的结果为 0 时,可以判断 BCE 不在 ABCD 里
package main
import (
"fmt"
)
func encode(str string) uint32 {
var value uint32 = 0
runes := []rune(str)
for _, v := range runes {
shift := uint32(v) - uint32('A')
value |= 1 << shift
}
return value
}
func Contains(str1, str2 string) bool {
val := encode(str1)
for _, v := range ([]rune(str2)) {
shift := uint32(v) - uint32('A')
if val&(1<<shift) == 0 {
return false
}
}
return true
}
func main() {
str1 := "ABCD"
str2 := "CD"
fmt.Println(Contains(str1, str2))
}
举一反三
1、变位词
- 如果两个字符串的字符一样,但是顺序不一样,被认为是兄弟字符串,比如bad和adb即为兄弟字符串,现提供一个字符串,如何在字典中迅速找到它的兄弟字符串,请描述数据结构和查询过程。
方法:先排序,再比较是否相等
package main
import "fmt"
func QuickSort(runes []rune, left, right int) {
if left < right {
m := part(runes, left, right)
QuickSort(runes, left, m-1)
QuickSort(runes, m+1, right)
}
}
func part(runes []rune, left, right int) int {
n := runes[left]
for left < right {
for left < right && runes[right] >= n {
right--
}
runes[left] = runes[right]
for left < right && runes[left] <= n {
left++
}
runes[right] = runes[left]
}
runes[left] = n
return left
}
func FindBrother(strs []string, str string) []string {
var res []string
strRunes := []rune(str)
QuickSort(strRunes, 0, len(strRunes)-1)
strSorted := string(strRunes)
for _, v := range strs {
tmp := []rune(v)
QuickSort(tmp, 0, len(tmp)-1)
if strSorted == string(tmp) {
res = append(res, v)
}
}
return res
}
func main() {
strs := []string{"abc", "cba", "agt"}
fmt.Println(FindBrother(strs, "bac"))
}