如果你想在校招中顺利拿到更好的offer,阿秀建议你多看看前人的经验 ,比如准备简历实习上岸经历校招总结阿里、字节、腾讯、美团等一二线大厂真实面经也欢迎来一起参加秋招打卡活动 等;如果你是计算机小白,学习/转行/校招路上感到迷茫或者需要帮助,可以点此联系阿秀;免费分享阿秀个人学习计算机以来的收集到的好资源,点此白嫖;如果你需要《阿秀的学习笔记》网站中求职相关知识点的PDF版本的话,可以点此下载

# 1128. 等价多米诺骨牌对的数量 好题,真的很好的题

力扣原题链接(点我直达) (opens new window)

给你一个由一些多米诺骨牌组成的列表 dominoes

如果其中某一张多米诺骨牌可以通过旋转 0 度或 180 度得到另一张多米诺骨牌,我们就认为这两张牌是等价的。

形式上,dominoes[i] = [a, b]dominoes[j] = [c, d] 等价的前提是 a==cb==d,或是 a==db==c

0 <= i < j < dominoes.length 的前提下,找出满足 dominoes[i]dominoes[j] 等价的骨牌对 (i, j) 的数量。

示例:

输入:dominoes = [[1,2],[2,1],[3,4],[5,6]]
输出:1
1
2

提示:

  • 1 <= dominoes.length <= 40000
  • 1 <= dominoes[i][j] <= 9

# 第一版,直接遍历,超出时间限制

    int numEquivDominoPairs(vector<vector<int>>& dominoes) {
    int cut = 0;
	for (int i = 0; i < dominoes.size(); ++i) {
		for (int j = i + 1; j < dominoes.size(); ++j) {
			if ((dominoes[i][0] == dominoes[j][0] && dominoes[i][1] == dominoes[j][1]) || (dominoes[i][0] == dominoes[j][1] && dominoes[i][1] == dominoes[j][0]))
				cut++;
		}
	}

	return cut;
        
    }
1
2
3
4
5
6
7
8
9
10
11
12

# 第二版,自己定义unordered_map的键值,为其他类型

执行用时 :52 ms, 在所有 cpp 提交中击败了87.56%的用户

内存消耗 :21 MB, 在所有 cpp 提交中击败了100.00%的用户

实例:https://blog.csdn.net/zhangpiu/article/details/49837387?utm_source=blogxgwz9

struct KEY
{
	int minNum;
	int maxNum;

	KEY(int f, int s) : minNum(f), maxNum(s) {}
};

struct HashFunc
{
	std::size_t operator()(const KEY& key) const
	{
		using std::size_t;
		using std::hash;

		return ((hash<int>()(key.minNum)
			^ (hash<int>()(key.maxNum) << 1)) >> 1);
	}
};

struct EqualKey
{
	bool operator () (const KEY& lhs, const KEY& rhs) const
	{
		return lhs.minNum == rhs.minNum
			&& lhs.maxNum == rhs.maxNum;
	}
};

int numEquivDominoPairs(vector<vector<int>>& dominoes) {

	unordered_map<KEY,int,HashFunc,EqualKey> unmp;

	int cut = 0;
	int maxNum=0, minNum=0;
	for (auto &n:dominoes) {
		minNum = min(n[0], n[1]);
		maxNum = max(n[0], n[1]);

		if (unmp.find({ minNum,maxNum }) != unmp.end()) {
			cut += unmp[{ minNum, maxNum }];
			unmp[{minNum, maxNum}]++;
		}
		else
			unmp[{minNum,maxNum}]++;
	}

	return cut;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 第三版,参考别人的,会更快一点了

执行用时 :48 ms, 在所有 cpp 提交中击败了95.27%的用户

内存消耗 :21.1 MB, 在所有 cpp 提交中击败了100.00%的用户

int numEquivDominoPairs(vector<vector<int>>& dominoes) {
	unordered_map<int, int> ret;
	int cut = 0,minNum=0,maxNum=0;

	for (auto& a : dominoes) {
		maxNum = max(a[0], a[1]);
		minNum = min(a[0], a[1]);
		if (ret.find(minNum * 10 + maxNum) != ret.end()) {
			cut += ret[minNum * 10 + maxNum];
		}
		ret[minNum * 10 + maxNum] += 1;

	}

	return cut;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 第四版,别人的写法,化为数学公式来做的

执行用时 :44 ms, 在所有 cpp 提交中击败了97.76%的用户

内存消耗 :21.1 MB, 在所有 cpp 提交中击败了100.00%的用户

int numEquivDominoPairs(vector<vector<int>>& dominoes) {
        map<int, int> ret;
        int count = 0;
        
        for(int i  = 0; i < dominoes.size(); ++i)
        {
            int k = 0;
            int m = dominoes[i][0];
            int n = dominoes[i][1];
            (m > n) ? k = n * 10 + m : k = m * 10 + n;//这种表达式也是可以的
            ret[k] += 1;
        }
        
        for(auto iter = ret.begin(); iter != ret.end(); ++iter)
        {
            count += iter->second * (iter->second - 1) / 2;
        }

        return count;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 第五版,结合一下,最快的

执行用时 :40 ms, 在所有 cpp 提交中击败了99.00%的用户

内存消耗 :21 MB, 在所有 cpp 提交中击败了100.00%的用户

int numEquivDominoPairs(vector<vector<int>>& dominoes) {

	unordered_map<int, int> ret;
	int k = 0, m = 0, n = 0;
	for (int i = 0; i < dominoes.size(); ++i)
	{
		m = dominoes[i][0];
		n = dominoes[i][1];
		(m > n) ? k = n * 10 + m : k = m * 10 + n;//这种表达式也是可以的
		ret[k] += 1;
	}
	int count = 0;
	for (auto &iter:ret)
	{
		count += iter.second * (iter.second - 1) / 2;
	}

	return count;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19