题目链接:https://leetcode-cn.com/problems/hand-of-straights/
题意:
爱丽丝有一手(hand)由整数数组给定的牌。
现在她想把牌重新排列成组,使得每个组的大小都是 W,且由 W 张连续的牌组成。
如果她可以完成分组就返回 true,否则返回 false。
注意:此题目与 1296 重复:https://leetcode-cn.com/problems/divide-array-in-sets-of-k-consecutive-numbers/
方法一:哈希表统计(效果一般)
class Solution {
public:
bool isNStraightHand(vector<int>& hand, int groupSize) {
int len = hand.size();
map<int,int> mp;//哈希表
if(len%groupSize!=0) return false;//如果长度不是groupSize的整数倍,说明不是所要的
sort(hand.begin(),hand.end());
for(auto& num:hand)
{
mp[num]++;
}
for(auto iter=mp.begin();iter!=mp.end();iter++)
{
if(iter->second==0)//匹配数目为0,要么是匹配完了,要么是没有这个数
continue;
else
{
int val = iter->second;//val记录当前key值对应的的value值
int index = 0;
while(index<groupSize)//遍历后续的几个键值
{
mp[iter->first+index]-=val;
if(val<0)//不够减,说明凑不了,返回false
return false;
index++;
}
}
}
return true;//能遍历完,说明都匹配过了
}
};
方法二:队列+滑动窗口(效果最优)
class Solution {
public:
bool isNStraightHand(vector<int>& hand, int W) {
int n = (int)hand.size();
if (n % W) return false;
int left = 0, right = 0;//相同值元素的左右端点,左闭右开[left,right)
sort(hand.begin(), hand.end());//元素排序
deque<int> window; //用来保存滑动窗口中的元素个数
deque<int> nums; //用来保存滑动窗口中的元素值
while (right < n) {
while (right < n && window.size() < W) { //没达到滑动窗口大小W,继续添加元素
while (right < n && hand[left] == hand[right]) right++; //相同元素值,继续找右端点
window.push_back(right-left); //保存当前元素个数
nums.push_back(hand[left]);//保存当前元素值
left = right;//下一个元素起始位置
}
if (window.size() < W) return false; //滑动窗口内元素个数达不到W,结束
for (int i = 1; i < W; i++) { //找到一组顺子
window[i] -= window[0]; //所有元素减去相同的频率,剩下的可以用于下面的顺子组合
if (window[i] < 0 || nums[i] != nums[i-1] + 1) return false; //元素不够用或者相邻元素值相差不为1无法组成顺子,结束
}
window.pop_front();//移除首个元素个数
nums.pop_front();//移除首个元素
while (!window.empty() && window[0] == 0) { //继续移除元素个数为0的元素
window.pop_front();
nums.pop_front();
}
}
return true;
}
};