题目
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/hand-of-straights/
1.描述
Alice
手中有一把牌,她想要重新排列这些牌,分成若干组,使每一组的牌数都是 groupSize
,并且由 groupSize
张连续的牌组成。
给你一个整数数组 hand
, 其中 hand[i]
是第 i
张牌的值,和一个整数 groupSize
。如果她可能按照题给条件重新排列这些牌,返回 true
。否则,返回 false
。
2.示例
- 示例 1:
输入:hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
输出:true
解释:Alice 手中的牌可以被重新排列为 [1,2,3],[2,3,4],[6,7,8]。
- 示例 2:
输入:hand = [1,2,3,4,5], groupSize = 4
输出:false
解释:Alice 手中的牌无法被重新排列成几个大小为 4 的组。
解题思路
此题可以使用排序+哈希表解决。
我们首先按照从小到大的顺序对手牌进行排序,然后从左往右一次遍历数组选出每个大小为groupSize
的牌组,并使用哈希表将每张已使用过的牌进行标记。一旦无法满足牌组条件,即下一张可用牌牌值不是当前牌牌值加一,即返回false
;如果选出了所有牌组,返回true
。
算法
1.计算手牌数m
,如果m
不是groupSize
的整数倍,返回假;如果groupSize
为1
,返回true
;
2.对手牌进行排序,初始化标记已使用手牌的哈希表hash
;
3.从第一张开始,依次选出每个牌组的牌:
- 如果当前牌没有被使用过,选中当前牌作为当前牌组的第一张牌,并标记为
cur
; - 从下一个位置开始,依次选出牌组的每一张牌,一张牌能作为牌组的下一张牌的条件是该牌没被使用过,并且牌值不等于当前牌,如果从左往右第一张可用牌的大小就超过了
cur+1
,则返回false
; - 如果满足牌组条件,更新已选牌
cur
为当前牌,将该牌标记为已使用,并更新下一张牌的可选初始位置为当前牌的下一位置。 - 如果选牌过程中达到了手牌最末位置的下一位置,说明无法完成选牌,返回
false
。
4.遍历完手牌,返回true
。
代码
class Solution {
public:
bool isNStraightHand(vector<int>& hand, int groupSize) {
int m = hand.size();//手牌数
if(m % groupSize != 0) return false;//如果手牌数不是组牌数的整数倍,返回假
if(groupSize == 1) return true;//如果组牌数是1,返回真
sort(hand.begin(), hand.end());//对手牌排序
vector<int> hash(m, 0);//哈希表,存储哪些手牌被用过了,键为下标,值为是否被用过
for(int i = 0; i < m; ++i){//顺序遍历排序后的手牌
if(hash[i]>0) continue;//如果手牌被用过了,跳出本次循环
int cur = hand[i];//如果手牌没被用过,选中作为当前牌组的第一张牌
int j;//标记当前正在选当前牌组的第几张牌
int k = i + 1;//标记正在验证的手牌,依次往后遍历,验证该手牌是否可以作为当前牌组的下一张牌
for(j = 1; j < groupSize; ++j){//依次选出当前牌组的各张牌
while(k<m && (hash[k]>0 || hand[k]==cur)){
//在满足还未遍历到手牌最后一个位置的下一个位置的条件下,
//如果该手牌被用过了,或者该手牌的值等于上一张已选中手牌的值
//则遍历下一张手牌,否则跳出该循环
k++;
}
//跳出循环后
//如果此时已经选到了手牌最后一个位置的下一个位置
//则停止当前牌组的选择工作,跳出循环
if(k==m) break;
//如果满足以上条件的手牌无法与已选手牌构成顺子,返回假
if(hand[k]!=++cur) return false;
//否则更新已选牌为当前牌
cur = hand[k];
//并且将其标记为已使用
++hash[k];
//更新下一次选牌的开始位置为当前牌的下一个位置
++k;
//继续选牌组的下一张牌
}
//判断循环的跳出方式,如果未选完当前牌组就跳出了,返回假
if(j!=groupSize) return false;
}
//选完了所有牌组,返回真
return true;
}
};
复杂度分析
时间复杂度: O(mlogm)
。m
为手牌数,排序的时间消耗为O(mlogm)
,选牌的时间消耗为O(m+((m/groupSize)*groupSize))
,综合时间复杂度为O(mlogm)
。
空间复杂度: O(m)
。哈希表的空间消耗。
更多知识内容分享:
力扣个人主页https://leetcode-cn.com/profile/articles/
CSDN个人主页https://blog.csdn.net/qq_39255924
牛客个人主页https://blog.nowcoder.net/newcoderthewarrior