如何判断字符串/集合是否为另一者的子集?赎金信问题最优实现咨询
判断字符串/集合是否为另一子集的最佳方法(针对赎金信问题)
问题说明
给定两个字符串
ransomNote和magazine,若ransomNote可由magazine中的字母构造而成(magazine中的每个字母在ransomNote中仅能使用一次),则返回true,否则返回false。想知道判断一个字符串/集合是否为另一个字符串/集合的子集的最佳方法是什么,有没有比手动统计每个字符更好的实现方式?现有实现代码如下:
def canConstruct(self, ransomNote: str, magazine: str) -> bool: c1, c2 = Counter(ransomNote), Counter(magazine) for letter in c1: if not (letter in c2 and c2[letter] >= c1[letter]): return False return True
优化实现方案
1. 极致简洁的Counter减法实现
你的现有代码已经利用了collections.Counter的特性,其实还能进一步简化——利用Counter的减法运算:当magazine的字符完全覆盖ransomNote的需求时,Counter(ransomNote) - Counter(magazine)会得到空的Counter对象,直接判断这个结果是否为空即可:
from collections import Counter def canConstruct(self, ransomNote: str, magazine: str) -> bool: return not Counter(ransomNote) - Counter(magazine)
原理:Counter的减法会保留计数大于0的键值对,只有当magazine中每个字符的数量都不小于ransomNote时,减法结果才会是空,此时返回True。
2. 空间优化的数组统计实现
如果追求更低的空间复杂度(尤其是处理超大字符串时),可以用固定大小的数组来统计字符(因为只涉及小写字母),避免使用Counter的额外开销:
def canConstruct(self, ransomNote: str, magazine: str) -> bool: # 初始化26个字母的计数数组 char_count = [0] * 26 # 统计magazine中每个字符的数量 for c in magazine: char_count[ord(c) - ord('a')] += 1 # 遍历ransomNote,逐个减少计数 for c in ransomNote: idx = ord(c) - ord('a') char_count[idx] -= 1 # 若计数为负,说明magazine中该字符不足 if char_count[idx] < 0: return False return True
这种方法的空间复杂度为O(1)(数组大小固定为26),在性能敏感场景下表现更优。
总结
- 若优先考虑代码简洁性,Counter减法实现是最优选择,一行核心逻辑即可完成判断。
- 若优先考虑空间效率,数组统计法更合适,无需导入额外模块,且内存开销极小。
内容的提问来源于stack exchange,提问作者Alec
相关产品推荐
相关产品推荐

