代码取自他人以下仅仅是本人的一些见解:
#include <iostream>
#include <queue> // 包含小根堆优先队列所需的头文件
#include <unordered_map> // 包含无序映射所需的头文件
using namespace std;
// 函数:判断是否能构成顺子
bool canFormStraight() {
int n, m;
cin >> n >> m; // 输入牌的总数n和每组顺子的长度m
priority_queue<int, vector<int>, greater<int>> q; // 定义小根堆优先队列,用于存储牌的数字,以便后续顺序处理
unordered_map<int, int> arr; // 使用无序映射记录每种牌的数量
while (n--) { // 循环读取n张牌的数字,并统计每种牌的数量
int num;
cin >> num;
arr[num]++; // 记录当前数字的数量加1
q.push(num); // 将当前数字压入优先队列中,保证从小到大排列
}
while (!q.empty()) { // 循环处理优先队列中的元素,直到队列为空
int number = q.top(); // 获取队列顶部(最小值)的牌的数字
q.pop(); // 弹出队列顶部的牌
if (arr[number] == 0) continue; // 如果该牌的数量已经为0,则直接跳过当前循环,处理下一张牌
for (int i = 0; i < m; i++) { // 遍历每组顺子的长度
int cnt = arr[number + i]--; // 获取当前牌及其后续牌的数量,并将当前牌的数量减1
if (cnt == 0) return false; // 如果当前牌及其后续牌的数量为0,则无法构成顺子,返回false
}
}
return true; // 若能顺利构成若干组m长度的顺子,则返回true
}
int main() {
int t;
cin >> t; // 输入测试用例数量t
while (t--) { // 循环处理每个测试用例
if (canFormStraight()) cout << "YES" << endl; // 判断是否能构成顺子,如果能,则输出YES
else cout << "NO" << endl; // 如果不能,则输出NO
}
return 0;
}
-
小根堆优先队列(priority_queue<int, vector<int>, greater<int>>):
- 小根堆是一种特殊的堆,堆中每个节点的值都小于或等于其子节点的值。在C++中,可以使用
priority_queue
来实现小根堆。 - 在这个题目中,小根堆优先队列的作用是将牌的数字按从小到大的顺序排列,以便后续按顺序处理。
- 小根堆是一种特殊的堆,堆中每个节点的值都小于或等于其子节点的值。在C++中,可以使用
-
无序映射(unordered_map<int, int>):
- 无序映射是C++中的一种关联容器,它存储键值对,并且可以快速查找指定键对应的值。在无序映射中,键是唯一的,但键值对的存储顺序是不确定的。
- 在这个题目中,无序映射用于记录每种牌的数量,键是牌的数字,值是该数字对应的牌的数量。
-
q.push(num) 保证从小到大排列的原理:
- 在C++的
priority_queue
中,如果不指定比较器,默认情况下会使用less
来比较元素,这会使得优先队列变成大根堆,即根节点的值最大。而我们在声明priority_queue
时指定了greater<int>
比较器,这意味着优先队列会按照元素的反序排列,即根节点的值最小。 - 因此,当我们将牌的数字压入优先队列时,由于使用了
greater<int>
比较器,优先队列会自动按从小到大的顺序排列,这样就保证了牌的数字从小到大的顺序。
- 在C++的