《剑指offer》面试题61:扑克牌中的顺子

更多剑指offer面试习题请点击:《剑指offer》(第二版)题集目录索引

一、题目

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


二、解题思路

  这里我们可以把五张牌看作一个数组,数组里面有五个数字(大小王均看作0)。接下来要做的事就是判断这五个数字是否连续。

  首先我们把这个数组进行排序,这里我是自己写了一个直插排序。然后因为0比较特殊(可以看作任何数字),我们用一个for循环统计出数组中0(即大小王)出现的次数times_of_zero。接下来我们就可以遍历数组判断数组元素是否连续。

  遍历数组时要记得从第一个非0元素开始。判断后一个数和前一个数数值之差gab
  1. 如果gab == 0,那表示这两个数相等(是顺子),直接返回false;
  2. 如果gab == 1,属于正常现象,表示这两个数是连续的(两张牌是连续的);
  3. 如果gab > 1 ,表示这两张牌之间差了gab-1张牌。因为0可以变成任意数,那就可以用gab-1个0来填补中间的空缺,使之连续。

  循环过程中,如果出现times_of_zero < 0的情况,那表示这五张牌中空缺太多了,没那么多0让你来补(一副牌就2两个大小王),那么就可以判断这副牌不是顺子;如果循环结束后times_of_zero >= 0这说明五张牌肯定能组成顺子,返回true。


三、代码实现

// 直插排序
void Insert(int* numbers, int length)
{
    if (nullptr == numbers || length <= 1)
        return;

    int i = 0;
    int end = 0;
    for (; i < length - 1; ++i)
    {
        end = i;
        while (end >= 0)
        {
            if (numbers[end] > numbers[end + 1])
            {
                int tmp = numbers[end];
                numbers[end] = numbers[end + 1];
                numbers[end + 1] = tmp;
            }
            --end;
        }
    }
}

// 判断是否为顺子
bool IsContinuous(int* numbers, int length)
{
    // 输入的数组不合法
    if (nullptr == numbers || length <= 0)
        return false;

    // 对数组进行排序
    Insert(numbers, length);

    // 记录数组中0的个数(牌中大小王的个数)
    int times_of_zero = 0;

    // 记录相邻两个元素的值差
    int gap = 0;

    // 统计0的个数
    int i = 0;
    for (; i < length; ++i)
    {
        if (0 == numbers[i])
            ++times_of_zero;
    }

    // 从非0位置开始计算
    i = times_of_zero;
    while (i < length - 1 && times_of_zero >= 0)
    {
        gap = numbers[i + 1] - numbers[i];

        // 两个数相等(对子)
        if (0 == gap)
        {
            return false;
        }
        // 两张牌不连续,用大小王来填充
        else
        {
            times_of_zero -= (gap - 1);
        }

        ++i;
    }
    return times_of_zero < 0 ? false : true;
}

四、测试代码

void Test(const char* testName, int* numbers, int length, bool expected)
{
    if (testName != nullptr)
        printf("-6%s begins: ", testName);

    if (IsContinuous(numbers, length) == expected)
        printf("Passed.\n");
    else
        printf("Failed.\n");
}

void Test1()
{
    int numbers[] = { 1, 3, 2, 5, 4 };
    Test("Test1", numbers, sizeof(numbers) / sizeof(int), true);
}

void Test2()
{
    int numbers[] = { 1, 3, 2, 6, 4 };
    Test("Test2", numbers, sizeof(numbers) / sizeof(int), false);
}

void Test3()
{
    int numbers[] = { 0, 3, 2, 6, 4 };
    Test("Test3", numbers, sizeof(numbers) / sizeof(int), true);
}

void Test4()
{
    int numbers[] = { 0, 3, 1, 6, 4 };
    Test("Test4", numbers, sizeof(numbers) / sizeof(int), false);
}

void Test5()
{
    int numbers[] = { 1, 3, 0, 5, 0 };
    Test("Test5", numbers, sizeof(numbers) / sizeof(int), true);
}

void Test6()
{
    int numbers[] = { 1, 3, 0, 7, 0 };
    Test("Test6", numbers, sizeof(numbers) / sizeof(int), false);
}

void Test7()
{
    int numbers[] = { 1, 0, 0, 5, 0 };
    Test("Test7", numbers, sizeof(numbers) / sizeof(int), true);
}

void Test8()
{
    int numbers[] = { 1, 0, 0, 7, 0 };
    Test("Test8", numbers, sizeof(numbers) / sizeof(int), false);
}

void Test9()
{
    int numbers[] = { 3, 0, 0, 0, 0 };
    Test("Test9", numbers, sizeof(numbers) / sizeof(int), true);
}

void Test10()
{
    int numbers[] = { 0, 0, 0, 0, 0 };
    Test("Test10", numbers, sizeof(numbers) / sizeof(int), true);
}

// 有对子
void Test11()
{
    int numbers[] = { 1, 0, 0, 1, 0 };
    Test("Test11", numbers, sizeof(numbers) / sizeof(int), false);
}

// 鲁棒性测试
void Test12()
{
    Test("Test12", nullptr, 0, false);
}

int main()
{
    Test1();
    Test2();
    Test3();
    Test4();
    Test5();
    Test6();
    Test7();
    Test8();
    Test9();
    Test10();
    Test11();
    Test12();

    system("pause");
    return 0;
}

五、测试结果

这里写图片描述

猜你喜欢

转载自blog.csdn.net/tianzez/article/details/80420172
今日推荐