在实际开发中,我们经常需要判断一个字符串
s1
是否可以由另一个字符串s2
中的字符重排或选择组成。这种问题在字母异位词(Anagram)检测、拼字游戏、字符消耗校验等场景中非常常见。
一、问题描述
给定两个字符串:
- •
source
:提供字母的原始字符串 - •
target
:需要判断是否可以由source
中的字母组成
要求判断 target 的每个字符 是否都可以在 source 中找到,并且字符数量也必须足够。
示例:
source | target | 结果 |
---|---|---|
"aabbcc" | "abc" | true |
"aabbcc" | "aabc" | true |
"aabbcc" | "aabcc" | false (因为 source 中只有两个 c ) |
二、解题思路
-
- 统计
source
中每个字符出现的次数
- 统计
-
- 遍历
target
,对每个字符减去一次计数
- 遍历
-
- 如果某个字符计数不足,则返回
false
;否则最终返回true
- 如果某个字符计数不足,则返回
时间复杂度 O(n+m) ,适合处理中等长度字符串。
三、Go语言实现
1. 代码实现
go
package main
import (
"fmt"
)
func CanFormString(source, target string) bool {
count := make(map[rune]int)
// 统计 source 中字符数量
for _, ch := range source {
count[ch]++
}
// 检查 target 是否可以被组成
for _, ch := range target {
if count[ch] > 0 {
count[ch]--
} else {
return false
}
}
return true
}
func main() {
fmt.Println(CanFormString("aabbcc", "abc")) // true
fmt.Println(CanFormString("aabbcc", "aabc")) // true
fmt.Println(CanFormString("aabbcc", "aabcc")) // false
}
四、进阶优化
✅ 1. 固定字符集优化
如果只处理 小写英文字母(a-z) ,可以用数组代替 map,提高性能:
go
func CanFormStringFast(source, target string) bool {
var count [26]int
for _, ch := range source {
count[ch-'a']++
}
for _, ch := range target {
index := ch - 'a'
if count[index] > 0 {
count[index]--
} else {
return false
}
}
return true
}
这种方式避免了哈希表开销,在性能敏感场景更高效。
✅ 2. 判断是否是字母异位词(Anagram)
如果想判断两个字符串是否是字母异位词(相同字符、相同数量),可以直接比较统计数组是否完全一致。
五、总结
通过本篇案例,我们学到了:
- • 如何用 Go 统计字符串字符频率
- • 如何判断一个字符串是否由另一个字符串组成
- • 如何通过固定字符集优化性能
这类问题是哈希计数、频率统计的典型应用,掌握后可以举一反三,解决更多字符串匹配、验证等问题。