在算法面试中,“扑克牌顺子”是一道典型的“逻辑分析+边界处理”题目。它看似考察简单的数字规律,实则需要兼顾“大小王的灵活替换”“重复牌排除”“数值范围校验”等多个细节。本文将从问题本质出发,拆解顺子判定的核心条件,详解“位运算优化去重”的实现思路,提供多语言可运行代码,并通过典型案例验证逻辑正确性,帮助读者掌握这类“规则型”算法题的解题框架。
一、问题定义与核心规则
1. 问题背景
从一副包含2个大王、2个小王(共54张)的扑克牌中随机抽取5张,判断是否能构成“顺子”。其中:
特殊规则:大小王可看作任意数字(用
0表示);数值映射:A=1,J=11,Q=12,K=13;
顺子定义:5张牌的数值能组成连续的5个整数(如
1,2,3,4,5、8,9,10,11,12)。
2. 示例解析
示例1:输入
[1,3,0,0,5](对应“红心A、黑桃3、小王、大王、方片5”)
大小王可替换为2和4,组成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个条件,缺一不可:
长度合法:输入数组长度必须为5(题目明确抽取5张牌);
数值合法:每张牌的数值必须在
0~13范围内(0代表大小王,1~13对应正常牌值);无重复牌:除大小王(
0)外,其他牌值不能重复(一副牌中同一数值的牌最多4张,但顺子中同一数值仅需1张);差值合法:非大小王牌的最大值与最小值之差必须小于5(因为大小王可填补空缺,若差值≥5,即使有4张大小王也无法填补空缺,如
1和6差值为5,需2,3,4,54个空缺,而大小王最多2张,无法满足)。
三、高效实现思路:位运算优化去重
1. 关键优化点:用位运算记录牌值出现次数
传统去重方法(如哈希表、数组)需额外存储空间,而本题中牌值范围固定(0~13),可通过位运算实现“零额外空间去重”:
用一个整数
flag的二进制位表示牌值是否出现:flag的第n位(从0开始计数)为1,表示牌值n已出现;例如
flag=0b1010(十进制10),表示牌值1和3已出现(第1位和第3位为1)。
核心操作:
检查牌值
n是否已出现:(flag >> n) & 1 == 1(右移n位后与1,判断第n位是否为1);标记牌值
n已出现:flag |= 1 << n(将1左移n位后与flag做或运算,将第n位置为1)。
2. 整体流程
边界校验:若数组长度≠5,直接返回
false;初始化变量:
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_num和min_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 True3. 代码说明
边界处理:严格校验数组长度和数值范围,避免非法输入(如
[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初始为-1、min_num初始为14,确保非0牌能正确更新最值(若全为0,max_num仍为-1,min_num仍为14,差值计算无意义,但此时“全0”本身符合顺子条件)。
七、总结
“扑克牌顺子”问题的核心是将业务规则转化为明确的算法条件,并通过位运算等技巧优化实现。解题过程中需兼顾“合法性校验”“去重”“最值计算”三个核心环节,同时注意边界场景(如全0、含非法值、重复牌)的处理。
这类“规则型”算法题在面试中频繁出现,其解题框架可总结为:
拆解规则:将题目描述转化为可量化的数学条件;
选择高效数据结构/算法:根据数据范围选择最优实现(如本题用位运算去重);
边界校验:覆盖所有异常场景(如空数组、非法值、极端案例);
提前优化:通过提前终止遍历等方式提升效率。
掌握该框架后,读者可轻松应对类似问题(如“判断五张牌是否为同花”“检测数组是否为连续序列”),提升算法分析与实现能力。
扑克牌顺子判定与优化实现
945

被折叠的 条评论
为什么被折叠?



