扑克牌顺子判定:原理、边界处理与高效实现(含多语言代码)

扑克牌顺子判定与优化实现
部署运行你感兴趣的模型镜像

在算法面试中,“扑克牌顺子”是一道典型的“逻辑分析+边界处理”题目。它看似考察简单的数字规律,实则需要兼顾“大小王的灵活替换”“重复牌排除”“数值范围校验”等多个细节。本文将从问题本质出发,拆解顺子判定的核心条件,详解“位运算优化去重”的实现思路,提供多语言可运行代码,并通过典型案例验证逻辑正确性,帮助读者掌握这类“规则型”算法题的解题框架。

一、问题定义与核心规则

1. 问题背景

从一副包含2个大王、2个小王(共54张)的扑克牌中随机抽取5张,判断是否能构成“顺子”。其中:

  • 特殊规则:大小王可看作任意数字(用0表示);

  • 数值映射:A=1,J=11,Q=12,K=13;

  • 顺子定义:5张牌的数值能组成连续的5个整数(如1,2,3,4,58,9,10,11,12)。

2. 示例解析

  • 示例1:输入[1,3,0,0,5](对应“红心A、黑桃3、小王、大王、方片5”)
    大小王可替换为24,组成1,2,3,4,5,判定为顺子

  • 示例2:输入[1,2,3,4,6](无大小王)
    最大值6与最小值1差值为5,无法组成连续5个整数,判定为非顺子

  • 示例3:输入[1,1,2,3,4](含重复牌)
    存在重复数字1,直接判定为非顺子

二、核心判定条件:拆解顺子的4个必要条件

要构成顺子,5张牌必须同时满足以下4个条件,缺一不可:

  1. 长度合法:输入数组长度必须为5(题目明确抽取5张牌);

  2. 数值合法:每张牌的数值必须在0~13范围内(0代表大小王,1~13对应正常牌值);

  3. 无重复牌:除大小王(0)外,其他牌值不能重复(一副牌中同一数值的牌最多4张,但顺子中同一数值仅需1张);

  4. 差值合法:非大小王牌的最大值与最小值之差必须小于5(因为大小王可填补空缺,若差值≥5,即使有4张大小王也无法填补空缺,如16差值为5,需2,3,4,54个空缺,而大小王最多2张,无法满足)。

三、高效实现思路:位运算优化去重

1. 关键优化点:用位运算记录牌值出现次数

传统去重方法(如哈希表、数组)需额外存储空间,而本题中牌值范围固定(0~13),可通过位运算实现“零额外空间去重”:

  • 用一个整数flag的二进制位表示牌值是否出现:

    • flag的第n位(从0开始计数)为1,表示牌值n已出现;

    • 例如flag=0b1010(十进制10),表示牌值13已出现(第1位和第3位为1)。

  • 核心操作:

  1. 检查牌值n是否已出现:(flag >> n) & 1 == 1(右移n位后与1,判断第n位是否为1);

  2. 标记牌值n已出现:flag |= 1 << n(将1左移n位后与flag做或运算,将第n位置为1)。

2. 整体流程

  1. 边界校验:若数组长度≠5,直接返回false

  2. 初始化变量

  • max_num:记录非大小王牌的最大值(初始为-1,因牌值最小为1);

  • min_num:记录非大小王牌的最小值(初始为14,因牌值最大为13);

  • flag:位运算标记牌值出现情况(初始为0);

  • 遍历每张牌: a. 若牌值n不在0~13,返回false; b. 若n=0(大小王),跳过(无需记录和参与最值计算); c. 若n已出现(通过flag判断),返回false; d. 标记n已出现(更新flag); e. 更新max_nummin_num; f. 若max_num - min_num ≥5,返回false(提前终止,无需继续遍历);

  • 遍历结束:所有条件满足,返回true

  • 四、多语言代码实现

    1. C++实现(位运算优化)

    #include <vector>
    using namespace std;
    
    class Solution {
    public:
        bool IsContinuous(vector<int> numbers) {
            // 条件1:数组长度必须为5
            if (numbers.size() != 5) {
                return false;
            }
            
            int max_num = -1;    // 非0牌的最大值(初始小于最小可能值1)
            int min_num = 14;    // 非0牌的最小值(初始大于最大可能值13)
            int flag = 0;        // 位运算标记牌值出现情况
            
            for (int i = 0; i < 5; ++i) {
                int cur = numbers[i];
                
                // 条件2:数值必须在0~13范围内
                if (cur < 0 || cur > 13) {
                    return false;
                }
                
                // 大小王(0)跳过,不参与去重和最值计算
                if (cur == 0) {
                    continue;
                }
                
                // 条件3:检查是否有重复牌(非0)
                if (((flag >> cur) & 1) == 1) {
                    return false;
                }
                
                // 标记当前牌值已出现
                flag |= 1 << cur;
                
                // 更新最大值和最小值
                if (cur > max_num) {
                    max_num = cur;
                }
                if (cur < min_num) {
                    min_num = cur;
                }
                
                // 条件4:提前判断差值是否超过5(优化效率)
                if (max_num - min_num >= 5) {
                    return false;
                }
            }
            
            // 所有条件满足,返回true
            return true;
        }
    };

    2. Python实现(简洁版)

    Python中整数支持无限位宽,位运算逻辑与C++一致,代码更简洁:

    # -*- coding:utf-8 -*-
    class Solution:
        def IsContinuous(self, numbers):
            # 条件1:数组长度必须为5
            if len(numbers) != 5:
                return False
            
            max_num = -1    # 非0牌的最大值
            min_num = 14    # 非0牌的最小值
            flag = 0        # 位运算标记牌值出现情况
            
            for num in numbers:
                # 条件2:数值必须在0~13范围内
                if num < 0 or num > 13:
                    return False
                
                # 大小王跳过
                if num == 0:
                    continue
                
                # 条件3:检查重复牌
                if (flag >> num) & 1 == 1:
                    return False
                
                # 标记牌值已出现
                flag |= 1 << num
                
                # 更新最值
                if num > max_num:
                    max_num = num
                if num < min_num:
                    min_num = num
                
                # 条件4:提前判断差值
                if max_num - min_num >= 5:
                    return False
            
            return True

    3. 代码说明

    • 边界处理:严格校验数组长度和数值范围,避免非法输入(如[1,2,3,4]长度为4,[15,0,0,0,0]含非法值15);

    • 效率优化:遍历过程中提前判断“差值≥5”和“重复牌”,无需遍历所有元素即可终止,平均时间复杂度为O(1)(固定遍历5个元素);

    • 空间优化:用flag整数的二进制位实现去重,空间复杂度为O(1)(无额外数据结构)。

    五、典型案例测试与分析

    为验证代码正确性,我们针对不同场景设计测试用例,覆盖所有核心逻辑:

    测试用例

    预期结果

    分析说明

    [1,3,0,0,5]

    true

    0替换为2、4,组成1-2-3-4-5

    [1,2,3,4,6]

    false

    无0,max-min=5,无法组成连续5数

    [1,1,2,3,4]

    false

    含重复牌1

    [0,0,0,0,0]

    true

    5张王,可组成任意顺子(如1-2-3-4-5)

    [10,11,12,13,0]

    true

    0替换为9,组成9-10-11-12-13

    [2,3,5,7,0]

    false

    max=7,min=2,差值=5,需4、6两个空缺,仅1张0无法填补

    [1,14,0,0,0]

    false

    含非法值14(超出13范围)

    测试代码(Python)

    if __name__ == "__main__":
        sol = Solution()
        test_cases = [
            [1,3,0,0,5],    # true
            [1,2,3,4,6],    # false
            [1,1,2,3,4],    # false
            [0,0,0,0,0],    # true
            [10,11,12,13,0],# true
            [2,3,5,7,0],    # false
            [1,14,0,0,0]    # false
        ]
        for case in test_cases:
            res = sol.IsContinuous(case)
            print(f"输入{case} → 结果:{res}")

    输出结果

    输入[1, 3, 0, 0, 5] → 结果:True
    输入[1, 2, 3, 4, 6] → 结果:False
    输入[1, 1, 2, 3, 4] → 结果:False
    输入[0, 0, 0, 0, 0] → 结果:True
    输入[10, 11, 12, 13, 0] → 结果:True
    输入[2, 3, 5, 7, 0] → 结果:False
    输入[1, 14, 0, 0, 0] → 结果:False

    所有测试用例均符合预期,验证了代码的正确性。

    六、常见误区与优化建议

    1. 常见误区

    • 忽略大小王数量限制:题目中大小王共4张(2大2小),但抽取5张牌时最多含4张0,代码中无需额外限制0的数量——因为“差值<5”已隐含“0的数量足够填补空缺”(如[0,0,0,0,5],max=5,min=5,差值=0<5,可组成1-2-3-4-5);

    • 误将“差值≤5”作为条件:正确条件是“差值<5”,例如[1,2,3,4,6]差值=5,即使有1张0也无法填补(需替换为5,而0仅1张,无法同时满足“替换5”和“组成连续5数”);

    • 用数组去重而非位运算:虽然数组(如count[14])也可实现去重,但位运算更节省空间(仅用1个整数),且操作更高效。

    2. 优化建议

    • 提前终止遍历:代码中“检查重复”和“差值≥5”时直接返回false,避免无效遍历,提升效率;

    • 明确变量初始化max_num初始为-1min_num初始为14,确保非0牌能正确更新最值(若全为0,max_num仍为-1min_num仍为14,差值计算无意义,但此时“全0”本身符合顺子条件)。

    七、总结

    “扑克牌顺子”问题的核心是将业务规则转化为明确的算法条件,并通过位运算等技巧优化实现。解题过程中需兼顾“合法性校验”“去重”“最值计算”三个核心环节,同时注意边界场景(如全0、含非法值、重复牌)的处理。

    这类“规则型”算法题在面试中频繁出现,其解题框架可总结为:

    1. 拆解规则:将题目描述转化为可量化的数学条件;

    2. 选择高效数据结构/算法:根据数据范围选择最优实现(如本题用位运算去重);

    3. 边界校验:覆盖所有异常场景(如空数组、非法值、极端案例);

    4. 提前优化:通过提前终止遍历等方式提升效率。

    掌握该框架后,读者可轻松应对类似问题(如“判断五张牌是否为同花”“检测数组是否为连续序列”),提升算法分析与实现能力。

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值