题意
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例2中,出现了两个0,可以把他们当成任何数,可以当作顺子中的任何一个缺少的数字,把它们当做3和4,那么这五个数就是1、2、3、4、5。是连续的,因此返回true。
解题思路
5 张牌是顺子的 充分条件 如下:
- 除大小王外,所有牌 无重复 ;
- 设此 5 张牌中最大的牌为 max ,最小的牌为 min (大小王除外),则需满足:
- max−min<5
因而,可将问题转化为:此 5 张牌是否满足以上两个条件?
- 当为0个大小王的时候,A、B、C、D、E,构成了顺子时,最大的牌为E,最小的牌为A,E-A=4<5。
- 当为1个大小王的时候,E-B=3<5。
- 当两个大小王的时候,C-A=2<5。
法1—集合+遍历
- 遍历五张牌,遇到大小王(即 0 )直接跳过。
- 判别重复: 利用 Set 实现遍历判重, Set 的查找方法的时间复杂度为 O(1) ;
- 获取最大 / 最小的牌: 借助辅助变量 max 和 min ,遍历统计即可。
class Solution
{
public:
bool isStraight(vector<int>& nums)
{
int max=0,min=14; //将max初始化为最小的牌(0);min更新为所有牌中最大的牌+1
unordered_set<int> uset;
for(int num:nums)
{
if(0==num)
{
//遇到大小王,跳过
continue;
}
else
{
if(uset.count(num))
{
//发现重复数字,不能构成顺子
return false;
}
else
{
max=max>num?max:num;
min=min<num?min:num;
uset.insert(num);
}
}
}
return (max-min)<5;
}
};
法2—排序+遍历
class Solution
{
public:
bool isStraight(vector<int>& nums)
{
/*
int max=0,min=14; //将max初始化为最小的牌(0);min更新为所有牌中最大的牌+1
unordered_set<int> uset;
for(int num:nums)
{
if(0==num)
{
//遇到大小王,跳过
continue;
}
else
{
if(uset.count(num))
{
//发现重复数字,不能构成顺子
return false;
}
else
{
max=max>num?max:num;
min=min<num?min:num;
uset.insert(num);
}
}
}
return (max-min)<5;
*/
sort(nums.begin(),nums.end());
int joker=0;
for(int i=0;i<4;i++)
{
if(0==nums[i])
{
joker++;
}
else
{
if(nums[i]==nums[i+1])
return false;
}
}
return nums[4]-nums[joker]<5;
}
};