【剑指offer-C++】JZ61:扑克牌顺子

【剑指offer-C++】JZ61:扑克牌顺子

    • 题目描述
    • 解题思路

题目描述

描述:现在有2副扑克牌,从扑克牌中随机五张扑克牌,我们需要来判断一下是不是顺子。

有如下规则:

  1. A为1,J为11,Q为12,K为13,A不能视为14;
  2. 大、小王为 0,0可以看作任意牌;
  3. 如果给出的五张牌能组成顺子(即这五张牌是连续的)就输出true,否则就输出false;
    4.数据保证每组5个数字,每组最多含有4个零,数组的数取值为 [0, 13];

要求:空间复杂度 O(1),时间复杂度 O(nlogn),本题也有时间复杂度 O(n) 的解法。

输入描述:输入五张扑克牌的值。

返回值描述:五张扑克牌能否组成顺子。

输入:[6,0,2,0,4]
返回值:true
说明:中间的两个0一个看作3,一个看作5 。即:[6,3,2,5,4]
这样这五张牌在[2,6]区间连续,输出true 
输入:[0,3,2,6,4]
返回值:true
输入:[1,0,0,1,0]
返回值:false
输入:[13,12,11,0,1]
返回值:false

解题思路

扑克牌顺子:最直观的想法是,首先想想顺子的特点是什么。首先顺子中不能出现相同的元素,其次顺子中各元素相差值为1,如果相差值大于1,可以使用万能牌0进行补齐,同时要考虑元素之间相差值过大从而导致万能牌无法补齐的情况。具体做法如下:首先对数组进行排序,然后统计数组中0出现的次数,即可用的万能牌张数,接着遍历剩余非0元素,如果剩余元素出现相等情况,则直接返回false,即不能构成顺子,反之统计元素之间的差值,注意,此处的差值是大于正常差值1的差值,最后根据万能牌的张数与元素之间的差值比较来判断返回true还是false。

bool IsContinuous( vector<int> numbers ) 
{
    // 首先对numbers数组进行排序
    sort(numbers.begin(),numbers.end());
    // 统计数组中0出现的个数
    int i=0; //i表示下标
    int zero_num=0; //zero_num表示0的个数
    while(numbers[i]==0) //i++放在循环条件中会导致数组异位
    {
        zero_num++;
        i++;
     }
     // 遍历数组统计元素间隔
     int interdiff=0; //interdiff表示元素间隔值
     for(;(i+1)<numbers.size();i++)
     {
        // 如果出现相等元素则不能构成顺子
        if(numbers[i+1]==numbers[i])
            return false;
        // 正常的顺子元素两者之间间隔为1 其余则是补万能牌
        interdiff+=(numbers[i+1]-numbers[i]-1);
     }
     // 如果功能牌可以补齐差值则返回true反之为false
     return zero_num>=interdiff?true:false;
}

idea:既然不能出现重复元素,那么可以使用集合uset来进行处理。具体做法如下:遍历数组,如果遇到0则直接跳过,反之查找uset中是否包含该元素,如果包含则表明出现了重复元素,直接返回false,反之将该元素加入uset中,然后分别统计数组中的最大值和最小值,最后根据最大值和最小值的差值是否超过5来判断返回true还是返回false。

bool IsContinuous( vector<int> numbers ) 
{
    // 集合 用于存储除0外的非重复元素
    unordered_set<int> uset;
    // 统计最大值 最小值 数值范围1~14
    int maxn=-1,minx=15;
    // 遍历数组元素
    for(int i=0;i<numbers.size();i++)
    {
        // 如果遇到0则跳过
        if(numbers[i]==0)
           continue;
        // 遇到相同元素则返回false
        if(uset.find(numbers[i])!=uset.end())
           return false;
        // 反之加入set
        else uset.emplace(numbers[i]);
        // 统计非0最大值
        maxn=max(maxn,numbers[i]);
        // 统计非0最小值
        minx=min(minx,numbers[i]);
     }
     // 如果最大值与最小值相差不超过5则一定可以构成顺子
     return (maxn-minx+1)<=5?true:false;
}

你可能感兴趣的:(剑指offer,c++,算法,排序算法)