题目:扑克牌顺子


现在有2副扑克牌,从扑克牌中随机五张扑克牌,我们需要来判断一下是不是顺子。
有如下规则:
1. A为1,J为11,Q为12,K为13,A不能视为14
2.大、小王为0,0可以看作任意牌
3.如果给出的五张牌能组成顺子(即这五张牌是连续的)就输出true,否则就输出false。
例如:给出数据[6,0,2,0,4]
中间的两个0一个看作3,一个看作5。即:[6,3,2,5,4]
这样这五张牌在[2,6]区间连续,输出true
数据保证每组5个数字,每组最多含有4个零,数组的数取值为[0, 13]


思路分析:在读题目的同时,我们应该去思考在什么情况下,扑克牌的五张牌不能构成顺子,同时也应该去思考解题的方法与技巧。

解法一:首先判断扑克牌要进行排序的张数,是否符合题目要求,如果是不符合题目要求的张数,可以直接返回false。在符合题目要求的同时,我们可以将扑克牌中的大小王(任意张)的个数计算出来,将扑克牌的顺序按大小排序完整后,进行下一轮的问题思考。

其次,可以想象一个问题,在两副牌中有四个大小王,所以可以分析如下情况:

当五张牌只有一张王的时候,按照大小顺序排序后,王应该在最前面,剩下的四张牌的大小其中相邻两张之间不能超过2,而且只能存在一次这种情况的发生,如果超过2,则直接返回false,例如0,1,4,5,6,如果没有超过,则返回true。

以此类推,有两张王的时候,剩下的四张牌的大小相邻两张牌之间不能超过3,或者有相邻两个两张牌之间的差距不能超过1,以此类推,就发现了解决问题的关键。


例子具体分析如下所示:

6

0

2

0

4

首先,判断0的个数为2,按顺序排放如下

0

0

2

4

6

从数字4的下标开始判断相邻值的大小,将相邻值的大小累加后得到一个值

0

0

2

4

6


根据判断可得,4-2-1 = 1,6-2-1 = 1,将两个值的大小相加后,与0的个数做比较:

当0的个数大于两个值的和时,返回true。

当0的个数小于两个值的和时,返回false。

当0的个数等于两个值的和时,返回true,由这几条可知该实例最后返回的结果为true。

其中C++代码如下所示:

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size() != 5)
            return false;
        sort(numbers.begin(), numbers.end());
        int numzero = 0;
        for(int i = 0; i != 5;i ++){//判断0的个数
            if(!numbers[i])
                numzero++;
        }
        
        int target = numzero + 1;//下标数
        int numgap = 0;
        while(target < 5){
            if(numbers[target - 1] == numbers[target])//像对子这种意外情况的发生
                return false;
            numgap += numbers[target] - numbers[target - 1] - 1;
            target++;
        }
        return (numzero >= numgap) ? true : false;
    }
};

时间复杂度为O(N)。


解法2:我们通过观察可以发现一个常识性的问题就是,因为是顺子,所以其最大值和最小值的差值不会超过5(不能允许有对的情况出现)。

以上述例子为例:

6

0

2

0

4

首先,判断0的个数为2,按顺序排放如下

0

0

2

4

6

判断除0以外的最大值和最小值之间的差距

6-2<5,则直接返回true


该方法C++代码如下所示:

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        int numzero = 0;
        sort(numbers.begin(), numbers.end());
        for(int i = 0; i < 5;i++){
            if(numbers[i] == 0)
                numzero++;
            else if(numbers[i] == numbers[i+1])
                return false;
        }
        return numbers[4] - numbers[numzero] < 5;
    }
};
这种方法属于按照常识性问题分析的办法,可以将一个复杂的问题化解成简单的东西,从而得出准确的答案。