
该方法用于检查字符串 word1 是否包含字符串 word2 中的**全部字符(含重复次数)**,顺序无关,但需确保每个字符的出现频次不超出 word1 中的实际数量。
在 Java 中,简单使用 String.contains() 或逐字符检查(如原代码中 word1.contains(itemPiece))无法处理字符重复计数问题——例如 word1 = "12345++" 和 word2 = "155",虽然 word1 中只有一个 '5',但原逻辑会两次匹配 '5',错误返回 true。
根本原因在于:contains() 是无状态、全局匹配,不消耗字符;而我们需要的是带频次约束的多对一匹配——即 word2 中每个字符必须在 word1 中有唯一对应(用过即失效)。
✅ 推荐解法是使用 ArrayList
import java.util.*;
public static boolean isItemUsable2(String word1, String word2) {
// 边界处理:空字符串视为有效(若业务要求 word2 为空时返回 true)
if (word2 == null || word2.isEmpty()) return true;
if (word1 == null) return false;
// 构建 word1 字符池(保留所有字符,含重复)
List availableChars = new ArrayList<>();
for (char c : word1.toCharArray()) {
availableChars.add(c);
}
// 尝试为 word2 中每个字符寻找唯一匹配
for (char target : word2.toCharArray()) {
// remove(Object) 返回 boolean:成功移除返回 true,未找到返回 false
if (!availableChars.remove((Character) target)) {
return false; // 某个字符缺失或已用尽
}
}
return true;
} ? 关键细节说明:
- availableChars.remove((Character) target) 使用的是 对象移除(remove(Object)),而非按索引移除(remove(int)),因此会删除列表中第一个匹配的字符实例;
- 强制类型转换 (Character) target 是必需的,否则会误调用 remove(int index) 导致 IndexOutOfBoundsException;
- 时间复杂度为 O(m × n),其中 m = word1.length(),n = word2.length()(ArrayList.remove() 平均 O(n));如需更高性能(如超长字符串),可改用 HashMap
统计频次(O(m + n))。
? 进阶优化(频次哈希表版,推荐用于大数据量):
public static boolean isItemUsable2Optimized(String word1, String word2) {
if (word2 == null || word2.isEmpty()) return true;
if (word1 == null) return false;
// 统计 word1 中各字符出现次数
Map charCount = new HashMap<>();
for (char c : word1.toCharArray()) {
charCount.put(c, charCount.getOrDefault(c, 0) + 1);
}
// 消耗 word2 中每个字符
for (char c : word2.toCharArray()) {
int count = charCount.getOrDefault(c, 0);
if (count <= 0) return false;
charCount.put(c, count - 1);
}
return true;
} ✅ 总结:解决“含重复字符的子集判定”问题,核心在于状态化匹配——要么动态消耗字符池(ArrayList),要么预统计频次(HashMap)。避免使用无状态的 contains(),它只回答“是否存在”,而非“是否足够”。










