面试题61. 扑克牌中的顺子

一、题目

题目链接:力扣

若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。

示例 1:

输入: [1,2,3,4,5]
输出: True

示例 2:

输入: [0,0,1,2,5]
输出: True

限制:

数组长度为 5 

数组的数取值为 [0, 13] .


二、题解

1、思路

  • 除大小王外,所有牌 无重复 ;
  • 设此 5 张牌中最大的牌为 max ,最小的牌为 min (大小王除外),则需满足:max - min < 5

满足上述两个条件即可组成顺子!

为什么呢?

无重复很好理解,为什么需要满足:max - min < 5呢?

首先假设满足不重复的条件,则有:

  • 假设不存在大王小王,也就是不存在0,直接max-min=x,那么x一定有,x>=4,什么情况一定是顺子呢?x=4,只有是4的时候才能保证是连续的;
  • 假设存在大王小王,也就是存在0,max-min=x,那么x一定有,x>=0,什么情况一定是顺子呢?max-min<=4。因为万能的0可以变成任何一个数字进行填充,如果max-min很小,那么0不仅可以填充min~max之间的数字,甚至可以填充到min~max范围外部,但是如果max-min>4,0甚至无法填充min~max之间的数字。
  • 具体来说:0的个数可能存在0~5个,我们一一分析。
  • 注意:max-min最大的时候是0填充在内部的时候,最小的时候是0填充在外部(即非零数字连续)的时候。
  • 0有1个,3<=max-min<=4;
  • 0有2个,2<=max-min<=4;
  • 0有3个,1<=max-min<=4;
  • 综上,max-min<5。

2、代码实现

🎯 哈希表 + 最值差

class Solution {
public:
    bool isStraight(vector<int>& nums) {
        unordered_set<int> set;
        int max_num = INT_MIN;
        int min_num = INT_MAX;
        
        for(auto& num : nums)
        {
            if(num == 0)continue;
            else
            {
                // 统计最值
                max_num = max(max_num, num);
                min_num = min(min_num, num);
                
                if(set.find(num) != set.end())return false;// 重复,不能组成顺子
                else set.insert(num);// 无重复加入哈希表
            }
        }

        // 最大牌 - 最小牌 < 5 则可构成顺子
        return max_num - min_num < 5;
    }
};

🎯 排序 + 重复排除

易错点:

  • for循环中一定要在nums[i] != 0的时候才能和后面的对比!
  • 会不会少统计一个0?如果nums中存在4个及以下的0,下面的代码肯定没有问题,很好理解;如果存在5个0,肯定可以组成顺子,下面的代码可以完成判断嘛?nums[4] - nums[count_0] = 0 - 0 < 5,可以判断。
class Solution {
public:
    bool isStraight(vector<int>& nums) {
        int n = nums.size();
        int num_0 = 0;
        sort(nums.begin(), nums.end());
        for(int i = 0; i < n - 1; i++)
        {
            if(nums[i] == 0)num_0++;
            else if(nums[i] == nums[i+1])return false;
        }

        // num_0可以取值为0 1 2 3 4
        // nums[num_0]刚好是第一个不为0的数字(下标和实际数量差1)
        // num_0 = 0 1 2 3; 符合max - min < 5
        // num_0 = 4; 是顺子,下面的判断语句是nums[4]-nums[4],小于5,true
        // num_0 = 5; 是顺子,下面的判断语句是nums[4]-nums[4],num_0=4哦!小于5,true
        // num_0=4和5的时候都是顺子,因此此处设计成nums[4]-nums[4],刚好。
        return nums[n - 1] - nums[num_0] < 5;
    }
};

3、复杂度分析

🎯 哈希表 + 最值差

时间复杂度:O(n)=O(5)=O(1);

空间复杂度:O(n)=O(5)=O(1)。

🎯 排序 + 重复排除

时间复杂度:O(nlogn)=O(5log5)=O(1);

空间复杂度:O(1)。

4、运行结果

🎯 哈希表 + 最值差

🎯 排序 + 重复排除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kashine

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值