题目描述:
给你一个由一些多米诺骨牌组成的列表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) 的数量。
示例:
输入:dominoes = [[1,2],[2,1],[3,4],[5,6]]
输出:1
提示:
1 <= dominoes.length <= 40000
1 <= dominoes[i][j] <= 9
blahblahblah,,,对于算法基础较为薄弱的我,一开始只能想到暴力解题。综合了诸多大佬的解题思路,不禁感慨,在此做了一个简单地汇总。
分析:
概括说来,题目的目的其实就是求出等价牌的排列组合。因此关键在于找出等价牌的数量,再运用排列组合公式即可求出答案。
比如对于[1,2]这张牌有n张等价牌,那么(i,j)的数量就是C(n,2),所以我们要做的是找出所有有等价牌的牌,然后找出它们对应等价牌的数量(count)。再count*(count-1)/2即可。(与顺序无关,因此要去重)
在此附上源代码(c++ version):
class Solution {
public:
int numEquivDominoPairs(vector<vector<int>>& dominoes)
{
int num = 0;
map<pair<int,int>,int> total;
for (int i=0;i<dominoes.size();i++)
{
int ten=min(dominoes[i][0],dominoes[i][1]);
int one=max(dominoes[i][0],dominoes[i][1]);
total[{ten,one}]++;
}
for (auto i:total)
{
int rec=i.second;
num+=rec*(rec-1)/2;
}
return num;
}
};
此外,题解给出的一种比较取巧的办法,我是想不出来,在此也做一下说明。(说明为摘录内容,自己还没理解透彻)
分析:
使用统一的编码对二元组进行编码,这里采用小的做十位数,大的做个位数的策略,然后使用一个vector进行计数,每次看当前编码已有的个数,使用当前的多米诺骨牌可以和之前的每一对形成新的一对,所以更新 num+=arr[rec];
class Solution {
public:
int numEquivDominoPairs(vector<vector<int>>& dominoes)
{
int num = 0;
vector<int> arr(100);
for (auto it:dominoes)
{
int rec=it[0]>it[1]?it[1]*10+it[0]:it[0]*10+it[1];
num+=arr[rec];
arr[rec]++;
}
return num;
}
};
我们再来看看用哈希表做,解题思路都大同小异,先上代码(java version):
public int numEquivDominoPairs3(int[][] dominoes) {
Map<Integer, Integer> map = new HashMap<Integer,Integer>();
for (int[] temp : dominoes) {
int num = Math.min(temp[0], temp[1])*10
+ Math.max(temp[0], temp[1]);
map.put(num, map.getOrDefault(num, 0)+1);
}
int result = 0;
for (Integer times : map.values()) {
result += times*(times-1)/2;
}
return result;
}
ps:再对“Map.getOrDefault(Object key, V defaultValue);”做一下简单的解释
如果在Map中存在key,则返回key所对应的的value。
如果在Map中不存在key,则返回默认值。
例如:
map.put(num, map.getOrDefault(num, 0) + 1);
表示:
value默认从1开始,每次操作后num对应的value值加1
可以用来统计数字出现的次数!