描述
给你一个由一些多米诺骨牌组成的列表 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-equivalent-domino-pairs/
求解
class Solution {
public:
// 方法一, 暴力解法
// 超时未通过
int numEquivDominoPairs_vio(vector<vector<int>> &dominoes) {
const int n = dominoes.size();
int count = 0;
for (int i = 0; i < n - 1; ++i) {
for (int j = i + 1; j < n; ++j) {
if (isDominoes(dominoes[i], dominoes[j])) {
++count;
}
}
}
return count;
}
// 方法二,利用查找表
// 低效率通过
int numEquivDominoPairs_2e(const vector<vector<int>> &dominoes) {
const int n = dominoes.size();
int count = 0;
std::unordered_map<int, vector<vector<int>>> record; // <和, 点对数组>记录,用于快速查找
for (auto &dominoe : dominoes) {
int sum = dominoe[0] + dominoe[1];
if (record.count(sum) > 0) {
const auto &vecs = record[sum];
for (const auto &vec : vecs) {
if (isDominoes(dominoe, vec)) {
++count;
}
}
}
record[sum].push_back(std::move(dominoe));
}
return count;
}
// 方法三,参考官方解答
// 1 <= dominoes[i][j] <= 9,因此对每对的两个数字编码,10*min(x,y) + max(x,y)肯定总是小于100
int numEquivDominoPairs_3e(const vector<vector<int>> &dominoes) {
vector<int> record(100, 0); // 100做记录足够了
int res = 0;
for (const auto &p : dominoes) {
int val = p[0] < p[1] ? 10 * p[0] + p[1] : 10 * p[1] + p[0];
res += record[val];
++record[val];
}
return res;
}
// 方法四,hash散列,重定义等价性计数,就是速度太慢
// 函数对象实现hash计算
struct dominoeHash {
std::size_t operator()(const vector<int> &vec) const {
std::hash<int> intHash;
return vec[0] < vec[1] ? intHash(vec[0]) ^ intHash(vec[1]) : intHash(vec[1]) ^ intHash(vec[0]);
}
};
// 函数对象实现equal_to
struct dominoeEqualTo {
bool operator()(const vector<int> &vec1, const vector<int> &vec2) const {
return (vec1[0] == vec2[0] && vec1[1] == vec2[1]) || (vec1[0] == vec2[1] && vec1[1] == vec2[0]);
}
};
int numEquivDominoPairs(const vector<vector<int>> &dominoes) {
// todo 使用lambda表达式
// auto const &hashcode = [](const vector<int> &vec) {
// std::hash<int> intHash;
// return vec[0] < vec[1] ? intHash(vec[0]) ^ intHash(vec[1]) : intHash(vec[1]) ^ intHash(vec[0]);
// };
//
// auto const &equalDominoe = [](const vector<int> &vec1, const vector<int> &vec2) {
// return (vec1[0] == vec2[0] && vec1[1] == vec2[1]) || (vec1[0] == vec2[1] && vec1[1] == vec2[0]);
// };
// 使用函数对象实现hash计算和equal_to
int count = 0;
std::unordered_multiset<vector<int>, dominoeHash, dominoeEqualTo> record;
for (const auto &p : dominoes) {
int num = record.count(p);
if (num > 0) {
count += num;
}
record.emplace(p.begin(), p.end());
}
return count;
}
private:
inline bool isDominoes(const vector<int> &vec1, const vector<int> &vec2) const {
return (vec1[0] == vec2[0] && vec1[1] == vec2[1]) || (vec1[0] == vec2[1] && vec1[1] == vec2[0]);
}
};