机考E卷100分题 - 斗地主之顺子

题目描述

斗地主扑克牌游戏中, 扑克牌由小到大的顺序为:3,4,5,6,7,8,9,10,J,Q,K,A,2,玩家可以出的扑克牌阵型有:单张、对子、顺子、飞机、炸弹等。

其中顺子的出牌规则为:由至少5张由小到大连续递增的扑克牌组成,且不能包含2。

例如:{3,4,5,6,7}、{3,4,5,6,7,8,9,10,J,Q,K,A}都是有效的顺子;而{J,Q,K,A,2}、 {2,3,4,5,6}、{3,4,5,6}、{3,4,5,6,8}等都不是顺子。

给定一个包含13张牌的数组,如果有满足出牌规则的顺子,请输出顺子。

如果存在多个顺子,请每行输出一个顺子,且需要按顺子的第一张牌的大小(必须从小到大)依次输出。

如果没有满足出牌规则的顺子,请输出No。

输入描述

13张任意顺序的扑克牌,每张扑克牌数字用空格隔开,每张扑克牌的数字都是合法的,并且不包括大小王:

2 9 J 2 3 4 K A 7 9 A 5 6

不需要考虑输入为异常字符的情况

输出描述

组成的顺子,每张扑克牌数字用空格隔开:

3 4 5 6 7

示例1

输入

2 9 J 2 3 4 K A 7 9 A 5 6
1

输出

3 4 5 6 7
1

说明

13张牌中,可以组成的顺子只有1组:3 4 5 6 7。

示例2

输入:

2 9 J 10 3 4 K A 7 Q A 5 6
1

输出:

3 4 5 6 7
9 10 J Q K A
12

说明

13张牌中,可以组成2组顺子,从小到大分别为:3 4 5 6 7 和 9 10 J Q K A

示例3

输入:

2 9 9 9 3 4 K A 10 Q A 5 6
1

输出:

No
1

说明

13张牌中,无法组成顺子。

解题思路

这个问题涉及解析一个包含13张扑克牌的数组,目的是识别出所有符合条件的有效顺子。顺子定义为至少包含5张按牌面大小顺序连续的扑克牌,不包括牌面为“2”的牌。

题目描述存在不明确之处,未具体说明是要求解最多数量的顺子,还是单个最长的顺子。

考虑以下示例:

4 5 6 7 8 6 7 8 9 10
1

如果目标是找到数量最多的顺子,答案将是两个独立的顺子:【4 5 6 7 8】和【6 7 8 9 10】。

如果目标是找到单个最长的顺子,答案则是【4 5 6 7 8 9 10】。

此外,如果【数量最多的顺子】,尽管【5 6 7 8 9】也是一个有效顺子,但在按照第二个示例的选择规则,它不是答案。这表明题目可能更倾向于寻找最长的顺子,且实际机考按照最长的去找,通过率高于数量最多。

Java

import java.util.*;
import java.util.stream.Collectors;

public class Main {
    // 静态初始化一个用于映射扑克牌面到数字的HashMap,以方便后续比较大小
    private static final Map<String, Integer> CARD_TO_NUMBER;

    static {
        // 初始化HashMap
        CARD_TO_NUMBER = new HashMap<>();
        // 将每张扑克牌对应的面值映射到一个整数,其中2被认为是最大的牌
        CARD_TO_NUMBER.put("3", 3);
        CARD_TO_NUMBER.put("4", 4);
        CARD_TO_NUMBER.put("5", 5);
        CARD_TO_NUMBER.put("6", 6);
        CARD_TO_NUMBER.put("7", 7);
        CARD_TO_NUMBER.put("8", 8);
        CARD_TO_NUMBER.put("9", 9);
        CARD_TO_NUMBER.put("10", 10);
        CARD_TO_NUMBER.put("J", 11);
        CARD_TO_NUMBER.put("Q", 12);
        CARD_TO_NUMBER.put("K", 13);
        CARD_TO_NUMBER.put("A", 14);
        CARD_TO_NUMBER.put("2", 16);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);  // 创建Scanner对象用于读取输入
        String[] cards = sc.nextLine().split(" ");  // 读取一行输入,并按空格分割成数组
        // 对输入的扑克牌按照定义的牌面大小进行排序
        Arrays.sort(cards, (a, b) -> CARD_TO_NUMBER.get(a) - CARD_TO_NUMBER.get(b));

        ArrayList<LinkedList<String>> straights = new ArrayList<>();  // 用于存储所有可能的顺子序列
        LinkedList<String> currentStraight = new LinkedList<>();  // 初始化当前正在检查的顺子序列
        currentStraight.add(cards[0]);  // 将排序后的第一张牌加入到当前顺子序列中
        straights.add(currentStraight);  // 将当前顺子序列加入到顺子列表中

        // 从第二张牌开始遍历所有牌
        for (int i = 1; i < cards.length; i++) {
            String card = cards[i];
            boolean added = false;  // 标记当前牌是否已被添加到某个顺子中

            // 遍历当前已存在的所有顺子序列,尝试将当前牌加入
            for (LinkedList<String> straight : straights) {
                // 判断当前牌是否可以追加到顺子的末尾
                if (CARD_TO_NUMBER.get(card) - CARD_TO_NUMBER.get(straight.getLast()) == 1) {
                    straight.add(card);
                    added = true;
                    break;
                }
            }

            // 如果当前牌没有加入到任何顺子中,创建一个新的顺子序列
            if (!added) {
                LinkedList<String> newStraight = new LinkedList<>();
                newStraight.add(card);
                straights.add(newStraight);
            }
        }

        // 筛选出长度至少为5的有效顺子序列
        List<LinkedList<String>> validStraights =
            straights.stream().filter(straight -> straight.size() >= 5).collect(Collectors.toList());

        // 如果没有找到有效的顺子序列,输出"No"
        if (validStraights.isEmpty()) {
            System.out.println("No");
        } else {
            // 将所有有效的顺子按照起始牌的大小进行排序并输出
            validStraights.stream()
                .sorted((a, b) -> CARD_TO_NUMBER.get(a.getFirst()) - CARD_TO_NUMBER.get(b.getFirst()))
                .forEach(straight -> System.out.println(String.join(" ", straight)));
        }
    }
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475

Python

# 导入Python标准库
from collections import deque

# 定义一个字典,用于映射扑克牌的牌面到数字,方便比较大小
CARD_TO_NUMBER = {
    '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8,
    '9': 9, '10': 10, 'J': 11, 'Q': 12, 'K': 13,
    'A': 14, '2': 16
}

 
# 使用input函数读取一行输入,并用split方法按空格分割字符串,得到牌面数组
cards = input().split()
# 根据牌面大小对牌进行排序
cards.sort(key=lambda x: CARD_TO_NUMBER[x])

straights = []  # 存储所有可能的顺子序列
current_straight = deque([cards[0]])  # 初始化当前顺子序列,使用deque提高效率
straights.append(current_straight)  # 将当前顺子序列添加到列表中

# 遍历输入的牌,从第二张牌开始
for card in cards[1:]:
    added = False  # 标记当前牌是否已被添加到某个顺子中

    # 尝试将当前牌加入到已存在的顺子序列中
    for straight in straights:
        # 判断当前牌是否可以追加到顺子末尾
        if CARD_TO_NUMBER[card] - CARD_TO_NUMBER[straight[-1]] == 1:
            straight.append(card)
            added = True
            break
    
    # 如果当前牌没有加入到任何顺子中,创建一个新的顺子序列
    if not added:
        new_straight = deque([card])
        straights.append(new_straight)

# 筛选出长度至少为5的有效顺子序列
valid_straights = [list(straight) for straight in straights if len(straight) >= 5]

# 如果没有找到有效的顺子序列,输出"No"
if not valid_straights:
    print("No")
else:
    # 对所有有效的顺子进行排序,并输出
    valid_straights.sort(key=lambda x: CARD_TO_NUMBER[x[0]])
    for straight in valid_straights:
        print(" ".join(straight))

 
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950

JavaScript

// 引入 readline 模块并创建接口用于读取来自标准输入(stdin)的数据
const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

// 定义一个映射扑克牌面到数字的对象,方便后续比较大小
const CARD_TO_NUMBER = {
    '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8,
    '9': 9, '10': 10, 'J': 11, 'Q': 12, 'K': 13,
    'A': 14, '2': 16
};

// 读取一行输入
rl.on('line', (input) => {
    // 按空格分割输入的字符串,得到牌的数组
    let cards = input.split(' ');
    // 根据牌面大小对牌进行排序
    cards.sort((a, b) => CARD_TO_NUMBER[a] - CARD_TO_NUMBER[b]);

    let straights = [];  // 存储所有可能的顺子序列
    let currentStraight = [cards[0]];  // 初始化当前顺子序列
    straights.push(currentStraight);  // 将当前顺子序列加入到列表中

    // 从第二张牌开始遍历所有牌
    for (let i = 1; i < cards.length; i++) {
        let card = cards[i];
        let added = false;  // 标记当前牌是否已被添加到某个顺子中

        // 尝试将当前牌加入到已存在的顺子序列中
        for (let straight of straights) {
            // 判断当前牌是否可以追加到顺子的末尾
            if (CARD_TO_NUMBER[card] - CARD_TO_NUMBER[straight[straight.length - 1]] === 1) {
                straight.push(card);
                added = true;
                break;
            }
        }

        // 如果当前牌没有加入到任何顺子中,创建一个新的顺子序列
        if (!added) {
            let newStraight = [card];
            straights.push(newStraight);
        }
    }

    // 筛选出长度至少为5的有效顺子序列
    let validStraights = straights.filter(straight => straight.length >= 5);

    // 如果没有找到有效的顺子序列,输出"No"
    if (validStraights.length === 0) {
        console.log("No");
    } else {
        // 对所有有效的顺子进行排序,并输出
        validStraights.sort((a, b) => CARD_TO_NUMBER[a[0]] - CARD_TO_NUMBER[b[0]]);
        validStraights.forEach(straight => console.log(straight.join(' ')));
    }

    rl.close(); // 关闭readline接口
});
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061

C++

#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <map>
#include <list>

using namespace std;
int main() {
    // 定义一个映射扑克牌面到数字的map,方便后续比较大小
    map<string, int> card_to_number = {
        {"3", 3}, {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7},
        {"8", 8}, {"9", 9}, {"10", 10}, {"J", 11}, {"Q", 12},
        {"K", 13}, {"A", 14}, {"2", 16}
    };

    // 从标准输入读取一行数据
    string input;
    getline(cin, input);
    istringstream iss(input);
    vector<string> cards;
    string card;

    // 将输入的扑克牌存入vector
    while (iss >> card) {
        cards.push_back(card);
    }

    // 根据定义的牌面大小对牌进行排序
    sort(cards.begin(), cards.end(), [&card_to_number](const string& a, const string& b) {
        return card_to_number[a] < card_to_number[b];
    });

    // 用于存储所有可能的顺子序列
    vector<list<string>> straights;
    list<string> current_straight;
    current_straight.push_back(cards[0]);
    straights.push_back(current_straight);

    // 从第二张牌开始遍历所有牌
    for (size_t i = 1; i < cards.size(); i++) {
        bool added = false;  // 标记当前牌是否已被添加到某个顺子中
        for (auto& straight : straights) {
            // 判断当前牌是否可以追加到顺子的末尾
            if (card_to_number[cards[i]] - card_to_number[straight.back()] == 1) {
                straight.push_back(cards[i]);
                added = true;
                break;
            }
        }

        // 如果当前牌没有加入到任何顺子中,创建一个新的顺子序列
        if (!added) {
            list<string> new_straight;
            new_straight.push_back(cards[i]);
            straights.push_back(new_straight);
        }
    }

    // 筛选出长度至少为5的有效顺子序列
    vector<list<string>> valid_straights;
    for (const auto& straight : straights) {
        if (straight.size() >= 5) {
            valid_straights.push_back(straight);
        }
    }

    // 如果没有找到有效的顺子序列,输出"No"
    if (valid_straights.empty()) {
        cout << "No\n";
    } else {
        // 输出所有有效的顺子序列
        for (const auto& straight : valid_straights) {
            for (const auto& card : straight) {
                cout << card << " ";
            }
            cout << endl;
        }
    }

    return 0;
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182

C语言

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义扑克牌与其数值的映射关系结构体
typedef struct {
    char card[3];  // 扑克牌面(考虑到"10"有两个字符,所以数组大小为3)
    int value;     // 对应的数值
} CardMap;

// 扑克牌面到数值的映射表
CardMap card_to_number[] = {
    {"3", 3}, {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7}, {"8", 8}, {"9", 9}, 
    {"10", 10}, {"J", 11}, {"Q", 12}, {"K", 13}, {"A", 14}, {"2", 16}
};
int card_map_size = sizeof(card_to_number) / sizeof(card_to_number[0]);

// 用于比较扑克牌的函数
int compare_cards(const void *a, const void *b) {
    const char *card1 = *(const char **)a;
    const char *card2 = *(const char **)b;
    int value1 = 0, value2 = 0;

    for (int i = 0; i < card_map_size; ++i) {
        if (strcmp(card_to_number[i].card, card1) == 0) {
            value1 = card_to_number[i].value;
        }
        if (strcmp(card_to_number[i].card, card2) == 0) {
            value2 = card_to_number[i].value;
        }
    }

    return value1 - value2;
}

int main() {
    char input[100];  // 存储输入字符串
    char *cards[20];  // 存储分割后的扑克牌字符串指针
    int count = 0;    // 扑克牌数量

    // 读取一行输入
    fgets(input, sizeof(input), stdin);
    input[strcspn(input, "\n")] = 0;  // 移除换行符

    // 分割输入字符串
    char *token = strtok(input, " ");
    while (token != NULL) {
        cards[count++] = token;
        token = strtok(NULL, " ");
    }

    // 对扑克牌进行排序
    qsort(cards, count, sizeof(char *), compare_cards);

    // 动态分配二维数组来存储可能的顺子序列
    char **straights[count];
    int lengths[count];  // 存储每个顺子的长度
    for (int i = 0; i < count; ++i) {
        straights[i] = malloc(count * sizeof(char *));
        straights[i][0] = cards[i];
        lengths[i] = 1;
    }
    int num_straights = count;

    // 生成顺子序列
    for (int i = 0; i < count; ++i) {
        for (int j = 0; j < num_straights; ++j) {
            if (compare_cards(&cards[i], &straights[j][lengths[j] - 1]) == 1) {
                straights[j][lengths[j]++] = cards[i];
                break;
            }
        }
    }

    // 输出长度至少为5的顺子序列
    int found = 0;
    for (int i = 0; i < num_straights; ++i) {
        if (lengths[i] >= 5) {
            found = 1;
            for (int j = 0; j < lengths[i]; ++j) {
                printf("%s ", straights[i][j]);
            }
            printf("\n");
        }
        free(straights[i]);
    }

    if (!found) {
        printf("No\n");
    }

    return 0;
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
#牛客创作赏金赛#

主要记录自己的刷题日常,学而时习之。

全部评论

相关推荐

牛客41406533...:回答他在课上学,一辈子待在学校的老教授用三十年前的祖传PPT一字一句的讲解,使用谭浩强红皮书作为教材在devc++里面敲出a+++++a的瞬间爆出114514个编译错误来学这样才显得专业
点赞 评论 收藏
分享
bg:双非本,一段中小厂6个月测开实习今天发这个帖子主要是想聊一聊我秋招以来的一个发展我是在8月底辞职,打算秋招,可是看网上都说金九银十就想着自己就是一个普通本科生,现在九月份都是一些大神在争抢,所以9月份基本上没投,等到了10月份才开始秋招,可是这个时间好像已经有些晚了,今年秋招开启的格外早,提前到了7,8月份,我十月才开始,官网投了很多公司,没有任何一个面试机会,这个情况一直到了十月底才有了第一个面试,当时没有面试经验,所以不出意外的挂了后续就是漫长的投递,但是毫无例外没有面试,没有办法我只能另辟蹊径开始在BOSS上边投递,然后顺便也根据BOSS上边这个公司名称去浏览器搜索看看有没有官网投递渠道,毕竟官网上投递后还是可以第一时间被HR看到的,然后一直不停投递,一开始第一个星期基本上都是投的正式秋招岗位到了第二个星期才开始实习和正式一起投,到十一月底的时候已经沟通了700➕才有一共1个正式的,5个要提前实习的,3个实习的面试,最后结果是过了1个要提前实习的和2个实习的每次面试我都会复盘,发现这些小公司面试官问的五花八门,有的专问基础,有的专问项目,有的啥都问,不过自己也是看出来了一下门道,就是小公司不像大公司面试官那样能力比较强基本上你简历上边的他都会,然后会根据简历来问,小公司面试官他们更多的是看自己会什么,然后看看你简历上边哪些他也是会的然后来问,经过不断的复盘加上背各种各样面试题,到了11月底12月初才有了1个要提前实习的offer还有2个实习的offer,而且薪资待遇对我来说已经很可观了可是啊,人总是这样得了千钱想万钱,我又开始不满现状,但是此时的我面试能力经过这么多面试和复盘已经很强了,然后在十二月份运气爆棚,被极兔和小鹏补录捞起来面试,还有个百度测开的实习面试,这个时候因为有了offer所以感觉有了底气,面试也很自信,最后结果是全部都过了那个时候我感觉自己真的很厉害,我问了极兔那边的HR像我这样的双非本收到offer的在极兔有多少?他告诉我产研岗90%都是硕士,10%里边基本上都是211,985,想我这样的很少很少,那一刻感觉自己超级牛逼,小鹏就更不用说了,最后也是不出意外选择了小鹏所以我就我个人经历想对和我学历履历差不多的牛友一些建议第一:秋招一定要趁早,真到了9,10月,那个时候可能你投的结果可能还不如7,8,11月,第二:最好先拿小公司实习或者正式练练手,提升一下面试能力,我个人觉得因为小公司问的五花八门所以你会更加横向去提升自己能力,而且大公司其实面试没有那么难,除了一些非常卷的岗位,公司大神比较多会问的很难,一般好点的公司都不会问的那么难,他们也知道都是应届生不会要求那么高第三:当有一定能力后,就是坚持了,对于我们这样的学历,没有特别强的履历情况下,就是要抓住提前批和补录的机会,这个时候各方面不会卡的很严,是我们很好很好的一个机会第四:就是运气也是很重要的一部分,不过这个很难去说什么最后祝各位牛友都能收获自己满意的offer😁😁😁
秋招,不懂就问
点赞 评论 收藏
分享
评论
2
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务