1. 程式人生 > >字串包含

字串包含

題目描述

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