1. 问题背景与理解
今天遇到一道有趣的LeetCode题目(1128号),要求统计等价多米诺骨牌对的数量。题目描述很简单:给定一组多米诺骨牌,其中每张骨牌用[a,b]表示,如果两张骨牌可以通过旋转(即[a,b]和[b,a]视为相同)相互得到,就称它们是等价的。我们需要统计所有等价骨牌对的数量。
举个例子:
输入:dominoes = [[1,2],[2,1],[3,4],[5,6]]
输出:1
解释:只有[1,2]和[2,1]是等价的
2. 解题思路分析
2.1 暴力解法的问题
最直观的想法是双重循环遍历所有骨牌对,检查是否等价。这种方法时间复杂度是O(n²),当n=10⁴时,计算量会达到10⁸级别,显然会超时。
2.2 哈希表优化思路
更聪明的做法是利用哈希表(字典)来统计每种等价类的出现次数。对于每张骨牌[a,b],我们可以将其标准化为有序对(min(a,b), max(a,b)),这样旋转后的等价骨牌就会有相同的表示。
2.3 组合数学的应用
统计完每种等价类的数量后,对于出现k次的等价类,其中包含的等价对数量是C(k,2)=k*(k-1)/2。将所有等价类的这个值相加就是最终答案。
3. 代码实现详解
3.1 Python实现
python复制def numEquivDominoPairs(dominoes):
count = {}
for a, b in dominoes:
key = (min(a,b), max(a,b))
count[key] = count.get(key, 0) + 1
total = 0
for v in count.values():
if v >= 2:
total += v * (v - 1) // 2
return total
3.2 代码解析
- 初始化一个空字典count来记录每种标准化骨牌的出现次数
- 遍历所有骨牌,将其标准化为有序对(min,max)
- 在字典中更新该标准化骨牌的计数
- 最后遍历字典,对每个出现次数≥2的等价类计算组合数并累加
3.3 复杂度分析
- 时间复杂度:O(n),只需要遍历骨牌列表两次(一次统计,一次计算)
- 空间复杂度:O(n),最坏情况下需要存储所有不同的标准化骨牌
4. 优化与变种
4.1 进一步空间优化
可以使用整数代替元组作为字典键,例如将(a,b)表示为a*10+b(假设数字都是1位数),这样可以略微提升性能:
python复制key = min(a,b)*10 + max(a,b)
4.2 并行处理思路
对于大规模数据,可以考虑将骨牌分组后并行处理,最后合并结果。这在分布式系统中特别有用。
4.3 相似题目扩展
这种"标准化+哈希统计"的思路可以应用于许多相似问题,比如:
- 统计字符串的变位词对
- 寻找几何图形的等价类
- 图像特征匹配中的相似性检测
5. 常见错误与调试
5.1 边界条件
需要注意的特殊情况包括:
- 空输入列表
- 所有骨牌都相同
- 所有骨牌都不同
- 包含重复的完全相同的骨牌
5.2 性能陷阱
在Python中,使用元组作为字典键比使用自定义对象更高效。避免在循环内创建不必要的临时对象。
5.3 测试用例建议
好的测试用例应该包含:
python复制assert numEquivDominoPairs([]) == 0
assert numEquivDominoPairs([[1,2]]) == 0
assert numEquivDominoPairs([[1,2],[2,1]]) == 1
assert numEquivDominoPairs([[1,2],[2,1],[1,2]]) == 3
assert numEquivDominoPairs([[1,2],[3,4],[5,6]]) == 0
6. 实际应用场景
这种等价类统计在实际中有很多应用,比如:
- 社交网络中的用户相似度分析
- 电商系统中的商品相似推荐
- 生物信息学中的序列比对
- 计算机视觉中的特征匹配
理解这类问题的解法,可以帮助我们在面对实际工程问题时快速找到高效的解决方案。
