字串包含
題目描述
給定兩個分別由字母組成的字串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"))
}