华为OD机试真题-斗地主之顺子

题目描述:
在斗地主只扑克牌游戏中,扑克牌由小到大的顺序为: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}都是有效的顺子;
**而**{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
输出:3 4 5 6 7

public class PokerGame {
    private static final Logger log = LoggerFactory.getLogger(PokerGame.class);

    /**
     * 查找并打印给定扑克牌序列中的所有有效顺子
     * 顺子定义为连续的五张牌序列
     * 
     * @param cards 以空格分隔的牌值字符串,每张牌用2位数字表示,如"03 04 05 06 07 08 09 10 11 12 01 02 01"
     *               其中01代表A,11代表J,12代表Q,13代表K
     */
    public static void findValidSequences(String cards) {
        // 检查输入是否有效
        if (cards == null || cards.isEmpty()) {
            System.out.println("Invalid input.");
            return;
        }
        log.info("Input: {}", cards);
    
        // 将输入的字符串转换为整数数组并排序
        int[] cardValues = new int[13];
        String[] splitCards = cards.split(" ");
        if (splitCards.length != 13) {
            System.out.println("Invalid number of cards.");
            return;
        }
        // 遍历splitCards数组,将每个元素转换为对应的牌值,并存储在cardValues数组中
        for (int i = 0; i < splitCards.length; i++) {
            cardValues[i] = parseCardValue(splitCards[i]);
        }
        //排序
        Arrays.sort(cardValues);
    
        // 查找并输出所有有效的顺子
        List<List<Integer>> sequences = findSequences(cardValues);
        if (sequences.isEmpty()) {
            System.out.println("NO");
        } else {
            sequences.forEach(PokerGame::printSequence);
        }
    }

    private static int parseCardValue(String cardStr) {
        switch (cardStr) {
            case "2": return 2;
            case "3": return 3;
            case "4": return 4;
            case "5": return 5;
            case "6": return 6;
            case "7": return 7;
            case "8": return 8;
            case "9": return 9;
            case "10": return 10;
            case "J": return 11;
            case "Q": return 12;
            case "K": return 13;
            case "A": return 14;
            default: throw new IllegalArgumentException("Invalid card: " + cardStr);
        }
    }

    private static List<List<Integer>> findSequences(int[] sortedCards) {
        List<List<Integer>> sequences = new ArrayList<>();
        // 从第0张牌开始,遍历所有可能的顺子
        for (int i = 0; i <= sortedCards.length - 5; i++) {
            // 检查当前位置是否为有效顺子
            if (isSequence(sortedCards, i)) {
                List<Integer> sequence = new ArrayList<>();
                // 将当前顺子添加到结果列表中
                for (int j = i; j < i + 5; j++) {
                    sequence.add(sortedCards[j]);
                }
                sequences.add(sequence);
               // 跳过已使用的四张牌,只需移动到下一个待检查的起始位置
            }
        }
        return sequences;
    }

    private static boolean isSequence(int[] cards, int start) {
        int gap = 0; // 用于记录非顺序牌之间的差值
        // 检查起始位置是否为2,如果是,则不是有效顺子
        if (cards[start] == 2) {
            return false;
        }
        // 遍历5张牌,检查是否为顺子
        for (int i = start; i < start + 5; i++) {
            // 检查是否出现重复牌
            if (i > start && cards[i] == cards[i - 1]) {
                // 重复牌,不是有效顺子
                return false;
            }
            // 检查是否出现A和2之间的间隔
            if (cards[i] == 14 && i + 1 < start + 5 && cards[i + 1] == 2) {
                // A可以视为序列的开始,但与下一张牌之间的间隔必须为3(14-1=13, 13-10=3)
                gap = 3;
            } else if (cards[i] == 2 && i > start && cards[i - 1] == 14) {
                // 前面是A,这里是2,忽略前面的gap检查
                gap = 0;
            } else if (i > start) {
                // 检查间隙是否为1(除了A后面紧跟2的情况)
                if (cards[i] - cards[i - 1] != 1 + gap) {
                    return false;
                }
                gap = 0; // 重置gap
            }
        }
        return true;
    }

    private static void printSequence(List<Integer> sequence) {
        // 将整数列表转换为字符串并输出
        System.out.println(sequence.stream().map(PokerGame::convertValueToString).collect(Collectors.joining(" ")));
    }

    private static String convertValueToString(int value) {
        switch (value) {
            case 2: return "2";
            case 3: return "3";
            case 4: return "4";
            case 5: return "5";
            case 6: return "6";
            case 7: return "7";
            case 8: return "8";
            case 9: return "9";
            case 10: return "10";
            case 11: return "J";
            case 12: return "Q";
            case 13: return "K";
            case 14: return "A";
            default: throw new IllegalArgumentException("Invalid value: " + value);
        }
    }


    public static void main(String[] args) {
        String input = "2 9 J 2 3 4 K A 7 8 A 5 6";
        findValidSequences(input);
    }
华为OD机试真题-学生重新排队是一个典的编程问题,下面是问题和解决路: 问题描述: 有n个学生站成一排,每个学生都有一个独一无二身份ID。现在给定一个初始的学生排列顺序,以及一系列的交换操作,交换操作表示将两个学生的位置进行交换。请你编写一个算法,输出最终的学生排列顺序。 解决思路: 这个问题可以使用数组来表示学生的排列顺序。首先,我们需要根据初始的学生排列顺序构建一个映射表,将每个学生的ID与其在数组中的位置对应起来。然后,我们按照给定的交换操作,更新映射表中学生的位置信息。最后,根据更新后的映射表,构建最终的学生排列顺序。 具体步骤如下: 1. 构建映射表:遍历初始的学生排列顺序,将每个学生的ID与其在数组中的位置对应起来,可以使用哈希表来实现。 2. 执行交换操作:按照给定的交换操作,更新映射表中学生的位置信息。 3. 构建最终的学生排列顺序:根据更新后的映射表,构建最终的学生排列顺序。 下面是一个示例代码,用于解决这个问题: ```python def rearrange_students(initial_order, swap_operations): # 构建映射表 mapping = {} for i, student_id in enumerate(initial_order): mapping[student_id] = i # 执行交换操作 for swap in swap_operations: student1, student2 = swap mapping[student1], mapping[student2] = mapping[student2], mapping[student1] # 构建最终的学生排列顺序 final_order = [0] * len(initial_order) for student_id, position in mapping.items(): final_order[position] = student_id return final_order ``` 使用上述代码,你可以通过传入初始的学生排列顺序和交换操作,得到最终的学生排列顺序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值