剑指Offer--044-扑克牌顺子_让用户输入1-13之间的数6个判断是连对还是顺子还是其他! js-程序员宅基地

技术标签: 面试  算法  排序  github  优化  ┈┈【剑指offer】  

链接


牛客OJ:扑克牌顺子

九度OJ:http://ac.jobdu.com/problem.php?pid=1355

GitHub代码: 044-扑克牌顺子

CSDN题解:剑指Offer–044-扑克牌顺子

牛客OJ 九度OJ CSDN题解 GitHub代码
044-扑克牌顺子 1355-扑克牌顺子 剑指Offer–044-扑克牌顺子 044-扑克牌顺子

题意


题目描述

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)…

他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票
,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,
“Oh My God!”不是顺子…..LL不高兴了,他想了想,决定大\小王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。
上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。

LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。

样例输入

3 5 1 0 4

3 5 4 7 6

3 5 7 4 8

样例输出

So Lucky!

So Lucky!

Oh My God!

排序后看0能不能填补空缺


可以把5张牌看成由5个数字组成的数组。大、小王是特殊的数字,我们不妨把它们定义为0,这样就能和其他扑克牌区分开来了。

接下来我们分析怎样判断5个数字是不是连续的,最直观的方法是把数组排序。值得注意的是,由于0可以当成任意数字,我们可以用0去补满数组中的空缺。如果排序之后的数组不是连续的,即相邻的两个数字相隔若干个数字,但只要我们有足够的0可以补满这两个数字的空缺,这个数组实际上还是连续的。举个例子,数组排序之后为{0,1,3,4,5},在1和3之间空缺了一个2,刚好我们有一个0,也就是我们可以把它当成2去填补这个空缺。

于是我们需要做3件事:

  1. 首先把数组排序

  2. 再统计数组中的0的个数

  3. 最后统计排序之后的数组中相邻数字之间的空缺总数。

如果空缺的总数小于或者等于0的个数,那么这个数组就是连续的;反之则不连续。

最后,我们还需要注意一点:

如果数组中的非0数字重复出现,则该数组不是连续的。


#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

//  调试开关
#define __tmain main

#ifdef __tmain

#define debug cout

#else

#define debug 0 && cout

#endif // __tmain

class Solution
{
public:
    bool IsContinuous(vector<int> numbers)
    {
        if(numbers.size( ) == 0)
        {
            return false;
        }
        sort(numbers.begin( ), numbers.end( ));

        /// 统计前面0的个数
        int left = 0;
        while(numbers[left] == 0)
        {
            left++;
        }
        debug <<"left = " <<left <<endl;

        ///  然后看0能不能填补两个数之间的空缺
        for(int i = left + 1; i < numbers.size( ); i++)
        {
            debug <<numbers[i - 1] <<", " <<numbers[i] <<endl;

            // 如果数组中的非0数字重复出现,则该数组不是连续的。
            if(numbers[i] == numbers[i - 1])
            {
                return false;
            }
            else        //  否则填补空缺, 无空缺的情况不用单独判断(空缺为0)
            {
                left -= (numbers[i] - numbers[i - 1] - 1);
            }
        }
        debug <<"left = " <<left <<endl;
        if(left >= 0)
        {
            return true;
        }
        else
        {
            return false;
        }

    }
};


int __tmain( )
{
    Solution solu;

    int arr1[] = { 1, 3, 2, 6, 4 };
    vector<int> vec1(arr1, arr1 + 5);
    cout <<solu.IsContinuous(vec1) <<endl;

    int arr2[] = { 3, 5, 1, 0, 4, };
    vector<int> vec2(arr2, arr2 + 5);
    cout <<solu.IsContinuous(vec2) <<endl;

    int arr3[] = { 1, 0, 0, 1, 0 };
    vector<int> vec3(arr3, arr3 + 5);
    cout <<solu.IsContinuous(vec3) <<endl;
    return 0;
}

考虑题目的特殊含义


但是我们考虑一下子题目中特殊条件对顺子有什么要求

条件: 5张牌,顺子,除0之外不能重复

结论: 非0元素的极差(最大值最小值的差)不超过4, 非0元素不重复

  • 非0元素的极差不查过4

首先5张牌的顺子,即使包含了0,那么最大值和最小值的差值肯定不超过4,否则的话一定不是顺子

比如{ 1,2,3,4,6 },最大最小值的差(极差)为6-1=5>4

正好满足的情况,{1, 2, 3, 4, 5},极差刚好是4

可以填补的情况,0填补的位置分四种情况,前面 {0, 2, 3, 4, 5},,中间{1, 2, 0, 4, 5}和结尾{1, 2, 3, 4, 0,},以及混合情况,这些情况下极差都不可能超过4

这个比较好判断,我们维护一个非0的最大最小值,那么判断极差即可

  • 非0元素不重复

接着是怎么判断非0元素是否重复呢?

我们可以通过位运算,设置一个标识flag


    #define BIT_GET(number, pos) ((number) >> (pos) & 1)     /// 用宏得到某数的某位

    #define BIT_SET(number, pos) ((number) |= 1 << (pos))    /// 把某位置1

首次遇见一个元素number时候,就设置标识flag的第number位为1,下次通过检测第number即可发现此元素是否重复

代码如下


#define BIT_GET(number, pos) ((number) >> (pos) & 1)     /// 用宏得到某数的某位

#define BIT_SET(number, pos) ((number) |= 1 << (pos))    /// 把某位置1

#define BIT_CLR(number, pos) ((number) &= ~(1 << (pos))) /// 把某位清0

#define BIT_CPL(number, pos) ((number) ^= 1 << (pos))    /// 把number的POS位取反




class Solution
{

public:

    bool IsContinuous(vector<int> numbers)
    {

        if(numbers.size( ) != 5)
        {
            return false;
        }

        int min = INT_MAX;
        int max = INT_MIN;
        int flag = 0;



        for(int i = 0; i < numbers.size( ); i++)
        {

            int num = numbers[i];


            if(num < 0 || num > 13) //  牌只能在0~13之间
            {
                return false;
            }
            else if(num == 0)       //  0用来答题任何牌,因此不能参与最大最小牌的比对
            {
                continue;
            }



            //  非0元素不能重复
            if(BIT_GET(flag, num) == 1)     //  如果flag的第num位为1, 说明num重复
            {
                debug <<i <<", " <<num <<endl;
                return false;
            }
            else
            {
                BIT_SET(flag, num);     //  将标识flag的第num位置为0
            }

            //  寻找最大最小的牌
            if(num > max)
            {

                max = num;
            }

            if(num < min)
            {
                min = num;
            }
            debug <<"max = " <<max <<", min = " <<min <<endl;


            //  如果最大值和最小值的差值大于4, 那么必应不能补齐
            if(max - min > 4)
            {
                debug <<"max = " <<max <<", min = " <<min <<endl;
                return false;
            }
        }
        return true;


    }
};
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/gatieme/article/details/51427573

智能推荐

OPENCV2.4.7+VS2010+海康威视摄像头_sadp_lib-程序员宅基地

文章浏览阅读1k次。准备:VS2010,OpenCV2.4.7,海康威视网络PTZ摄像头,Win10操作系统。一.摄像头的安装1.按照说明书安装好摄像头,用网线连接在电脑上,配置电脑IP或者摄像头IP,保证摄像头和电脑在同一个网段,这时摄像头会提醒成功连接网络。2.从海康威视官网上下载SADP并安装(这个版本的SADP我下载下来以后装上了却用不了,后来我就下了比这个低一个版本的,可以使用),按照说明书在S..._sadp_lib

Web前端开发快速学习,0基础前端开发,web前端开发工程师找工作,web开发学什么-程序员宅基地

文章浏览阅读604次,点赞10次,收藏8次。自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

CentOS系统安装VNC详细步骤_centos如何用vnc-程序员宅基地

文章浏览阅读2k次。下面是总结的详细配置步骤,分享给大家。一、VNC远程控制CentOS系统1、查看CentOS系统中是否有安装vnc(默认安装)输入命令:rpm -q vnc vnc-server如果显示结果为:package vnc is not installedvnc-server-4.1.2-14.e15_3.1说明你机器上已经安装了vnc。如果没有,可以在centOS的软件_centos如何用vnc

datax的使用以及参数解释,快速入门版_datax 参数-程序员宅基地

文章浏览阅读4.8k次,点赞17次,收藏9次。datax的使用以及参数解释,快速入门版_datax 参数

JavaScript(二)——猜数字游戏_javascript猜数字游戏-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏79次。下面我们将会通过一个小案例——猜数字游戏,来直观地感受一下如何让JavaScript完成任务。设计要求假设你的老板给你布置了以下游戏设计任务要求:我想让你开发一个猜数字游戏。游戏应随机选择一个 100 以内的自然数, 然后邀请玩家在 10 轮以内猜出这个数字。每轮后都应告知玩家的答案正确与否,如果出错了,则告诉他数字是低了还是高了。并且应显示出玩家前一轮所猜的数字。一旦玩家猜对,或者用尽所有机会,游戏将结束。游戏结束后,可以让玩家选择再次开始。看到这个要求,首先我们要做的是将其分解成简单的可操作_javascript猜数字游戏

Java必须掌握的全局变量和局部变量(含面试大厂题和源码)-程序员宅基地

文章浏览阅读884次,点赞25次,收藏20次。在Java中,全局变量和局部变量的概念通常与类变量(有时被认为是全局变量)和方法内的变量(局部变量)相关联。虽然Java本身没有全局变量的概念,但类的静态变量经常被用作全局变量。

随便推点

ACM--HDOJ 2072--单词数--字符串--水_java acm单词数问题 #结束-程序员宅基地

文章浏览阅读1.2k次。HDOJ题目地址:传送门单词数Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 44934 Accepted Submission(s): 10992Problem Descr_java acm单词数问题 #结束

uniapp自定义tabbar必看_uniapp custom-tab-bar-程序员宅基地

文章浏览阅读9.5k次。方式一:实验证明,在根目录下新建custom-tab-bar目录,在目录中新建index.vue是行不通的,vue文件不会被编译方式二:将小程序四大法宝(wxss,json,wxml,js)直接搬过来,虽然tabbar有渲染在小程序上了,但是切换是没有效果的,所以还是行不通方式三(行得通)经过上面的两个尝试,还是乖乖的以vue的做法吧,用单页面的形式,通过v-show控制组件的隐藏和显示注意:v-show有时没有效果,因为v-show是通过display:none来控制的,它的权重没_uniapp custom-tab-bar

树莓派系列-3-连接到树莓派_树莓派 片选接到-程序员宅基地

文章浏览阅读1.3k次。我们用树莓派,估计是没有人会接着屏幕使用的,但是如果有需求也可以使用。如果我们不用屏幕来使用树莓派,那么就得使用SSH、VNC、还有我们的Windows远程工具了。1.SSH 需要在树莓派中开启SSH支持,开启SSH支持有多种方式,这里我就说说我用的,第一种 就是在我们烧写有系统的时候,在boot的分区里面新建一个不带任何后缀的ssh文件,最简单的方式就是新建txt文件,完了重命名为s..._树莓派 片选接到

【毕业设计】STM32化工厂系统-程序员宅基地

文章浏览阅读32次。整个系统以STM32 单片机作为核心控制器,通过DHT11检测温湿度,通过CO传感器检测CO浓度,通过火焰传感器检测火焰,通过红外传感器检测人,通过RFID模块检测刷卡,检测到的数据通过OLED显示并通过无线传输模块上传数据到手机APP,通过继电器控制水阀,通过蜂鸣器报警。

CSS三角、界面样式(cursor、input输入边框不改变颜色、textarea拖拽不改变大小)、vertical-align、溢出文字省略号显示、CSS初始化_html css input::cue-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏7次。vertical-align的可选值为:1. bottom: 图片的底线和文字的底线对齐,2. baseline:默认,图片的底线和文字的基线对齐,3. middle: 图片的中线和文字的中线对齐,4. top:图片的顶线和文字的顶线对齐。不同浏览器对有些标签的默认值是不同的,为了消除不同浏览器对HTML文本呈现的差异,所以需要进行CSS初始化。当我们选择input输入框,进行文字输入的时候,边框会改变颜色。textarea默认可以在右下角进行拖拽,改变输入框的大小。CSS初始化参考如下。_html css input::cue

【CS231N】5、神经网络静态部分:数据预处理等-程序员宅基地

文章浏览阅读84次。一、疑问二、知识点1. 白化​ 白化操作的输入是特征基准上的数据,然后对每个维度除以其特征值来对数值范围进行归一化。该变换的几何解释是:如果数据服从多变量的高斯分布,那么经过白化后,数据的分布将会是一个均值为零,且协方差相等的矩阵。该操作的代码如下:# 对数据进行白化操作:# 除以特征值 Xwhite = Xrot / np.sqrt(S + 1e-5)​ 警告:夸大的噪声。注意分母..._人工神经网络系统中的静态数据