【华为机考E卷】-“猜数字”题解思路java

算法每一题,成长每一天~

C0E7 猜数字

真题链接:【持续更新】2024华为 OD 机试E卷 机考真题库清单(全真题库)

思路

在这里插入图片描述

Java

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

/**
 * 猜数字
 */
public class C0E7 {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        int n = in.nextInt();

        // 读取输入
        String[] number = new String[n];
        String[] keys = new String[n];
        for (int i = 0; i < n; i++) {
            number[i] = in.next();
            keys[i] = in.next();
        }

        Set<Character> excepts = new HashSet<>(); // 不包含的数字

        // 特殊情况
        for (int i = 0; i < keys.length; i++) {
            if (keys[i].contains("4A")) {
                System.out.println(number[i]);
                return;
            }
            if (keys[i].equals("0A0B")) {
                for (int j = 0; j < 4; j++) {
                    excepts.add(number[i].charAt(j));
                }
            }
        }

        // 将输入转换成字符
        char[][] numberChar = new char[n][4];
        int[][] keyCount = new int[n][2];
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < 4; k++) {
                numberChar[j][k] = number[j].charAt(k);
            }
            keyCount[j][0] = keys[j].charAt(0) - '0'; // X
            keyCount[j][1] = keys[j].charAt(2) - '0'; // Y
        }

        String result;
        // 全量枚举,逐个比对
        OUT:
        for (int i = 9999; i >= 0; i--) {
            result = convert(i); // 转换为4位字符串
            char[] charArray = result.toCharArray();

            // 排除不包含的
            for (char c : charArray) {
                if (excepts.contains(c)) {
                    continue OUT;
                }
            }

            if (check(charArray, numberChar, keyCount)) {
                System.out.println(result);
                return;
            }

        }

        System.out.println("NA");
    }


    /**
     * 检查是否满足条件
     *
     * @param obj        待检查的数字
     * @param numberChar 输入的数字
     * @param keyCount   输入的数字对应的A B
     * @return
     */
    public static boolean check(char[] obj, char[][] numberChar, int[][] keyCount) {
        // 每一个输入的数字,与目标数字 obj 进行比较(每一个都需要满足)
        for (int i = 0; i < numberChar.length; i++) {
            char[] chars = numberChar[i];
            int same = keyCount[i][0];
            int like = keyCount[i][1];

            Set<Character> objSet = new HashSet<>();
            Set<Character> numSet = new HashSet<>();
            // 先判断 同位置
            for (int j = 0; j < 4; j++) {
                if (obj[j] == chars[j]) {
                    same--;
                } else {
                    objSet.add(obj[j]);
                    numSet.add(chars[j]);
                }
            }

            if (same != 0) {
                return false;
            }

            // ----- 这里有个易错的点:谜面多个数字匹配到谜底的同一个数字,会多次-1,是错误的!!
            // ----- 所以应该是匹配出一个就拿走一个,只能用 remove(),而不能用 contains()!!

            for (char c : objSet) {
                if (numSet.remove(c)) { // 比对一个移除一个
                    like--;
                }
            }

            if (like != 0) {
                return false;
            }
        }

        // 全部满足,返回 true
        return true;
    }

    public static String convert(int i) {
        String result = String.valueOf(i);
        if (i < 10) {
            result = "000" + result;
        } else if (i < 100) {
            result = "00" + result;
        } else if (i < 1000) {
            result = "0" + result;
        }
        return result;
    }
}

总结

1、敲 check()方法的时候,发现这里边还是有点逻辑的,容易考虑错误。比如方法中备注的,多个数字与一个数字相同时,只会记1个相同。但是如果使用 contains() 方法判断,则会匹配多次!所以改成 remove() ,匹配一个移除一个。
2、【重要】 对于这种判断规则比较多的情形,考虑全量枚举(如果枚举数量级不是很大)是一种比较好的思路。
3、【重要】 随机去重用Set集合,按位匹配用数组。对吗?可以形成经验么?

xx:题目不难,但是写了蛮久,还是在前面思路没有完全考虑清楚!!

xx:容器多次切换(字符串数组 --> 字符数组,字符数组 --> Set集合)也比较费时间,稍有不慎容易写错。后面看看有没有更简单的方法~


算法要多练多练多练!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值