
本文介绍一种准确判断字符串a是否包含字符串b中所有字符(含重复字符)的java实现方法,核心在于维护字符频次而非简单存在性检查,避免因忽略重复字符导致误判。
在字符串匹配场景中,仅检查“字符是否存在”是不够的——例如 word1 = "12345++" 和 word2 = "155",虽然 '5' 在 word1 中只出现一次,但 word2 要求两个 '5',此时应返回 false。原始实现使用 String.contains() 逐字符判断,却未考虑字符数量限制,因此会错误地将 "155" 判定为可用。
正确的思路是:将 word1 视为一个可消耗的字符资源池,每匹配 word2 中的一个字符,就从池中移除一个对应实例。这样能天然保证频次约束。
推荐解法是使用 ArrayList
以下是完整、健壮的实现:
import java.util.*;
public static boolean isItemUsable2(String word1, String word2) {
// 边界处理:空字符串逻辑
if (word2 == null || word2.isEmpty()) return true;
if (word1 == null) return false;
// 构建可修改的字符池
List word1Chars = new ArrayList<>();
for (char c : word1.toCharArray()) {
word1Chars.add(c);
}
// 逐个尝试消耗 word2 中的字符
for (int i = 0; i < word2.length(); i++) {
char target = word2.charAt(i);
// remove() 返回 true 表示成功移除一个匹配字符
if (!word1Chars.remove((Character) target)) {
return false; // 字符不足,立即失败
}
}
return true;
} ✅ 关键优势:
- 时间复杂度可控(平均 O(m×n),其中 m=word1.length, n=word2.length),适用于中小规模字符串;
- 逻辑清晰,无需手动计数或排序;
- 自动处理空字符串、null 等边界情况(已补充)。
⚠️ 注意事项:
- List.remove(Object) 依赖 equals(),务必强制转型为 Character(否则会误调 remove(int index) 重载);
- 若对性能有极高要求(如超长字符串),可升级为 HashMap
统计频次,将时间复杂度优化至 O(m + n); - 该方法区分大小写且不忽略空白符,如需忽略空格或转小写,应在预处理阶段统一转换。
总结:解决“含重复字符的子集判定”问题,本质是模拟资源分配过程。使用动态可变的字符列表,配合精准的单次移除语义,即可简洁、正确地实现频次敏感的包含性校验。










