剑指offer61.扑克牌中的顺子
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
解题思路:
先看下题目给的示例:[0,0,1,2,5],为什么这个能够成顺子,因为0代表大小王,可以当作顺子中的任何一个缺少的数字,组成 1 2 3 4 5
众所周知顺子中不能出现重复的牌,如果出现重复的牌肯定不是顺子 所以出现像 [ 0 , 0 , 2 , 2 , 5 ]这样的绝对不可能构成顺子
另一种像[0 , 7 , 5 , 9 , 2], 这个的最小值是2,最大值是9,差值是7,就算拥有大小王可以代替任何一个数字,也无法组成5个连续的数字,由[ 0,0, 1 , 2 , 4 ] , [ 0,0, 1 , 2 , 5 ] 可以看出最大牌和最小牌的跨度≤4
所以规则本质上就是,除大小王之外,顺子中的最大值和最小值之间的差值不会超过4
排序法:
代码实现1是排序,这样的话,重复的数字就一定会相邻,判断重复的数是否为0
class Solution {
public:
bool isStraight(vector<int>& nums) {
sort(nums.begin(),nums.end()); //先排序
int joker = 0;
for(auto e:nums)
{
if (e ==0)
joker++; //记录大小王的数量
}
for(int i = 0 ; i < 4; ++i)
{
if(nums[i]==nums[i+1] && nums[i]!=0) // 排序后相邻的牌在一起,但仅允许大小王重复
return false;
if(nums[4]-nums[joker]>=5) // 最大牌和最小牌点数相差不会超过4
return false; // nums[joker]为非0的最小值
}
return true;
}
};
Set容器去重:
代码实现2是利用set容器自动过滤掉重复的数,利用迭代器解引用出容器里最大和最小的值,看相差是否在4以内
PS:
(1) set<int>::iterator it = s.end(); s.end()并非获得容器最后一个元素的地址,而是最后一个元素的下一个地址,表示容器中的元素数量,--s.end()才是容器中最后一个元素的地址
(2) 注意指针加减运算优先于括号
(3) set插入数据的同时会返回插入结果, 用pair对组接收pair< set<int>::iterator , bool> , bool为pair的第二个数据,表示插入是否成功,若插入重复元素便会失败,值为false
class Solution {
public:
bool isStraight(vector<int>& nums) {
set<int> s; //利用set容器去掉重复元素
for(auto e :nums)
{
if(e==0) //遇到大小王直接跳
continue;
// set插入数据的同时会返回插入结果用pair对组接收pair< set<int>::iterator , bool>
// bool为pair的第二个数据,表示插入是否成功,若插入重复元素便为false
pair<set<int>::iterator, bool> ret = s.insert(e);
if(ret.second==false) //遇到非0重复数,直接返回false
return false;
}
int max = *--s.end(); //获取容器中最后一个元素
int min = *s.begin(); //获取容器中第一个元素
return max-min<=4;
}
};
