[LeetCode] 每日一题 1128. 等价多米诺骨牌对的数量(排序 + 哈希)
题目描述
给你一组多米诺骨牌 dominoes
。
形式上,dominoes[i] = [a, b]
与 dominoes[j] = [c, d]
等价 当且仅当 (a == c
且 b == d
) 或者 (a == d
且 b == c
) 。即一张骨牌可以通过旋转 0
度或 180
度得到另一张多米诺骨牌。
在 0 <= i < j < dominoes.length
的前提下,找出满足 dominoes[i]
和 dominoes[j]
等价的骨牌对 (i, j)
的数量。
题目链接
示例输入
示例 1
输入:dominoes = [[1,2],[2,1],[3,4],[5,6]]
输出:1
示例 2
输入:dominoes = [[1,2],[1,2],[1,1],[1,2],[2,2]]
输出:3
提示
1 <= dominoes.length <= 4 * 104
dominoes[i].length == 2
1 <= dominoes[i][j] <= 9
解题思路
这道题本质是一个组合统计问题,我们需要找出所有满足“等价”条件的多米诺骨牌对 (i, j)
。题目中定义的等价关系其实比较宽松:即 [a, b]
和 [b, a]
被视为相同。因此,我们可以通过一个简单排序策略来统一它们的表示方式。
具体来说,我们将每张牌 [a, b]
变换为 min(a, b) * 10 + max(a, b)
,这样就能将 [2, 5]
和 [5, 2]
统一表示为 25
,从而方便哈希处理。
由于数字范围限定在 1~9,我们可以直接用一个大小为 100 的数组模拟哈希表,统计每个牌型出现的次数。遍历每个多米诺时,假设当前是 j 位置的牌,之前已经统计过所有 i 位置的牌(i < j),我们只需要查一下之前这个牌型出现了几次即可,这些就构成了等价对。
这种做法既高效又简洁,非常适合面试中快速实现。
代码实现
class Solution {
public int numEquivDominoPairs(int[][] dominoes) {
int[] cnt = new int[100];
int ans = 0;
for (int[] domino : dominoes) {
int top = domino[0], bottom = domino[1];
if (top > bottom) {
top ^= bottom;
bottom ^= top;
top ^= bottom;
}
int pos = 10 * top + bottom;
ans += cnt[pos]++;
}
return ans;
}
}
复杂度分析
时间复杂度:O(n)
只遍历一次所有骨牌,每张骨牌的处理是常数时间空间复杂度:O(1)
使用固定长度的计数数组(100个元素),即常数级空间
总结
这道题是那种一眼看过去可能不清楚统计逻辑,但理清本质就非常容易下手的题。我的解法是直接把等价的两个方向规整成一种形式,再用计数数组模拟哈希统计。特别适合拿来练习哈希映射技巧 + 前缀累加组合数的思想,属于思维清晰即可高效拿分的题型💡
希望这篇分享能为你带来启发!如果你有任何问题或建议,欢迎在评论区留言,与我共同交流探讨。