题目来自LeetCode,链接:number-of-equivalent-domino-pairs。具体描述为:给你一个由一些多米诺骨牌组成的列表 dominoes。如果其中某一张多米诺骨牌可以通过旋转 0 度或 180 度得到另一张多米诺骨牌,我们就认为这两张牌是等价的。形式上,dominoes[i] = [a, b] 和 dominoes[j] = [c, d] 等价的前提是a == c且b == d,或是 a == d且b == c。在 0 <= i < j < dominoes.length 的前提下,找出满足 dominoes[i] 和 dominoes[j] 等价的骨牌对 (i, j) 的数量。提示:
- 1 <= dominoes.length <= 40000
- 1 <= dominoes[i][j] <= 9
示例:
输入:dominoes = [[1,2],[2,1],[3,4],[5,6]]
输出:1
一个很容易想到的思路就是用每个骨牌对做key,出现次数做value,最后的value假设为n,那么 就是此骨牌对的数量。当然,数组是做不了key的,一开始不知道这些数组都是长度为2所以先转了字符串,后来才发现数组长度都是2,那么就容易多了,直接转成一个两位数即可,不过由于可以逆序,所以需要约定生成的时候小数在前大数在后,比如[1,2]->12,[2,1]->12。又考虑到这里数字的大小不会超过100,所以可以不用字典/Map,直接用一个100长度的数组保存value(实际可能的数字只有45种,可以进一步减少空间需求的)。
计算骨牌对数的时候可以计算所有的 之和,但也可以在遍历过程中直接累加出来,这可以通过 看出来,遍历过程只要当前数组已经出现过,就将统计次数加上之前的次数,然后出现次数再+1。总的时间复杂度为 ,空间复杂度为 。
JAVA版代码如下:
class Solution {
public int numEquivDominoPairs(int[][] dominoes) {
int count = 0, key;
int[] record = new int[100];
for (int[] pair : dominoes) {
if (pair[0] < pair[1]) {
key = pair[0] * 10 + pair[1];
}
else {
key = pair[1] * 10 + pair[0];
}
count += record[key]++;
}
return count;
}
}
提交结果如下:
Python版代码如下:
class Solution:
def numEquivDominoPairs(self, dominoes: List[List[int]]) -> int:
recordLst = [0 for i in range(100)] #数字最大为99
count = 0
for x, y in dominoes:
key = min(x, y) * 10 + max(x, y) #[1,2]->12, [2,1]->12
count += recordLst[key] #(n+1)n/2-n(n-1)/2=n
recordLst[key] += 1
return count
提交结果如下: