当前位置: 首页 > article >正文

【华为OD-E卷 - 猜数字 100分(python、java、c++、js、c)】

【华为OD-E卷 - 猜数字 100分(python、java、c++、js、c)】

题目

一个人设定一组四码的数字作为谜底,另一方猜。
每猜一个数,出数者就要根据这个数字给出提示,提示以XAYB形式呈现,直到猜中位置。
其中X表示位置正确的数的个数(数字正确且位置正确),而Y表示数字正确而位置不对的数的个数。
例如,当谜底为8123,而猜谜者猜1052时,出题者必须提示0A2B。
例如,当谜底为5637,而猜谜者才4931时,出题者必须提示1A0B。
当前已知N组猜谜者猜的数字与提示,如果答案确定,请输出答案,不确定则输出NA

输入描述

  • 第一行输入一个正整数,0<N < 100。

接下来N行,每一行包含一个猜测的数字与提示结果

输出描述

  • 输出最后的答案,答案不确定则输出NA

备注

用例

用例一:
输入:
6
4815 1A1B
5716 0A1B
7842 0A1B
4901 0A0B
8585 3A0B
8555 2A1B
输出:
3585

python解法

  • 解题思路:
  • 目标:

根据用户的多次猜测结果,从所有可能的4位数字答案中推断唯一符合条件的答案。如果没有答案或有多个可能答案,返回"NA"。
关键逻辑:

每次猜测的结果表示为xAyB,其中x是数字和位置都正确的个数(称为A),y是数字正确但位置不正确的个数(称为B)。
遍历所有可能的4位数字组合,逐一验证是否符合所有猜测的结果条件。
主要功能模块:

getGuessResult: 计算某次猜测与答案的xAyB结果。
isValid: 验证某个答案是否满足所有的猜测结果。
generatePossibleAnswers: 生成所有可能的4位数字组合。
findAnswer: 在所有可能答案中找到唯一符合条件的答案。
实现细节:

使用回溯法生成所有可能的4位数字组合。
遍历所有组合,调用isValid验证是否符合所有猜测。
如果仅有一个符合条件的答案,返回该答案;否则返回"NA"

# 计算某次猜测的结果(xAyB格式)
def getGuessResult(guess, answer):
    countA = 0  # 记录A的数量(数字和位置都正确)
    countB = 0  # 记录B的数量(数字正确但位置不正确)
    answer_arr = [0] * 10  # 记录答案中每个数字的出现次数
    guess_arr = [0] * 10  # 记录猜测中每个数字的出现次数

    # 遍历猜测和答案的每一位
    for i in range(4):
        if guess[i] == answer[i]:
            # 数字和位置都正确,增加A计数
            countA += 1
        else:
            # 数字位置不正确,记录出现次数
            guess_arr[int(guess[i])] += 1
            answer_arr[int(answer[i])] += 1

    # 计算B的数量:取猜测和答案中每个数字的最小出现次数
    for i in range(10):
        countB += min(guess_arr[i], answer_arr[i])

    # 返回结果格式如 "xAyB"
    return f"{countA}A{countB}B"

# 验证某个答案是否满足所有的猜测结果
def isValid(answer, infos):
    for guess, result in infos:
        # 如果当前答案和某次猜测的结果不匹配,答案无效
        if getGuessResult(guess, answer) != result:
            return False
    return True

# 生成所有可能的4位数字组合
def generatePossibleAnswers():
    answers = []  # 存储所有可能的答案

    # 使用回溯法生成数字组合
    def backtrack(path):
        if len(path) == 4:
            # 如果路径长度为4,添加为一个可能答案
            answers.append("".join(path))
            return
        for i in range(10):  # 每次选择0-9中的一个数字
            backtrack(path + [str(i)])

    backtrack([])  # 从空路径开始回溯
    return answers

# 找到唯一符合条件的答案
def findAnswer(infos):
    # 生成所有可能的4位数字组合
    possible_answers = generatePossibleAnswers()

    # 筛选满足所有猜测结果的答案
    valid_answers = [ans for ans in possible_answers if isValid(ans, infos)]

    # 如果只有一个符合条件的答案,返回该答案;否则返回"NA"
    if len(valid_answers) == 1:
        return valid_answers[0]
    else:
        return "NA"

# 主程序入口
n = int(input())  # 读取猜测的次数
infos = [input().split() for _ in range(n)]  # 读取每次猜测及其结果
print(findAnswer(infos))  # 输出唯一符合条件的答案或"NA"

java解法

  • 解题思路
  • 目标:

找出唯一的4位数字密码secret,满足所有用户给出的线索clues。
每条线索由一个猜测和相应的提示(格式为xAyB)组成:
xA: 有x个数字与密码的数字和位置都正确。
yB: 有y个数字与密码的数字正确但位置不正确。
基本逻辑:

枚举所有可能的4位数字密码(0000到9999,共10000个)。
对每个密码,验证它是否满足所有的线索。
如果仅有一个密码满足所有线索,返回该密码;如果没有或有多个符合的密码,返回"NA"。
关键功能模块:

findSecret:
枚举所有可能的密码,验证每个密码是否满足所有线索。
如果仅有一个候选密码,返回该密码;否则返回"NA"。
isMatch:
验证某个密码是否满足所有的线索。
对每条线索,调用generateHint生成实际提示,与预期提示比较。
generateHint:
根据猜测和密码,计算提示值xAyB。
代码实现:

使用两层循环:
外层循环枚举所有可能密码。
内层循环验证密码是否满足每条线索

import java.util.*;

public class Main {
    // 存储用户给出的线索,每个线索由猜测和提示组成
    static String[][] clues;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 输入线索的数量
        int n = scanner.nextInt();
        clues = new String[n][2];
        // 读取每条线索(猜测和提示)
        for (int i = 0; i < n; i++) {
            clues[i][0] = scanner.next(); // 读取猜测
            clues[i][1] = scanner.next(); // 读取提示
        }

        // 输出唯一符合条件的密码或"NA"
        System.out.println(findSecret());
    }

    // 找到唯一符合线索的密码
    public static String findSecret() {
        List<String> candidates = new ArrayList<>(); // 存储符合条件的候选密码

        // 枚举所有可能的4位数字密码
        for (int i = 0; i < 10000; i++) {
            // 格式化成4位字符串(如 1 -> 0001)
            String secret = String.format("%04d", i);
            // 验证当前密码是否满足所有线索
            if (isMatch(secret)) {
                candidates.add(secret); // 如果满足,加入候选列表
            }
        }

        // 如果仅有一个候选密码,返回该密码;否则返回"NA"
        if (candidates.size() == 1) {
            return candidates.get(0);
        } else {
            return "NA";
        }
    }

    // 验证某个密码是否满足所有线索
    public static boolean isMatch(String secret) {
        // 遍历所有线索
        for (String[] clue : clues) {
            String guess = clue[0];          // 当前线索的猜测
            String expectedHint = clue[1];  // 当前线索的预期提示
            String actualHint = generateHint(guess, secret); // 根据当前密码生成实际提示

            // 如果实际提示与预期提示不一致,返回false
            if (!expectedHint.equals(actualHint)) {
                return false;
            }
        }
        // 如果所有线索均满足,返回true
        return true;
    }

    // 根据猜测和密码,生成提示(格式为xAyB)
    public static String generateHint(String guess, String secret) {
        int correctPosition = 0; // 记录数字和位置都正确的个数(A)
        int correctNumber = 0;   // 记录数字正确但位置不正确的个数(B)

        int[] guessCount = new int[10]; // 记录猜测中每个数字的出现次数
        int[] secretCount = new int[10]; // 记录密码中每个数字的出现次数

        // 遍历4位数字
        for (int i = 0; i < 4; i++) {
            if (guess.charAt(i) == secret.charAt(i)) {
                // 如果数字和位置都正确,增加A计数
                correctPosition++;
            } else {
                // 否则,记录数字的出现次数
                guessCount[guess.charAt(i) - '0']++;
                secretCount[secret.charAt(i) - '0']++;
            }
        }

        // 计算B值:取猜测和密码中每个数字出现次数的最小值
        for (int i = 0; i < 10; i++) {
            correctNumber += Math.min(guessCount[i], secretCount[i]);
        }

        // 返回提示值(如"1A2B")
        return correctPosition + "A" + correctNumber + "B";
    }
}

C++解法

  • 解题思路
更新中

C解法

  • 解题思路

更新中

JS解法

  • 解题思路

  • 目标:

找到一个唯一的4位数字组合,满足所有提示hints。
每条提示由一个猜测guess和结果result组成:
result的格式为xAyB,表示:
xA:有x个数字的位置和数值都正确。
yB:有y个数字的数值正确但位置不正确。
优化解法:

使用位操作和递归进行优化:
位操作用于记录每个位置可能的数字,减少枚举范围。
深度优先搜索(DFS)用于生成可能的密码组合并验证其有效性。
主要步骤:

初始化可能性数组:
每个位置的可能数字初始为(1 << 10) - 1(即0-9全部可能)。
根据提示逐步更新可能性数组,排除不符合的数字。
深度优先搜索生成候选密码:
按位置递归生成所有可能的4位数字组合。
对每个组合,验证是否满足所有提示。
验证密码有效性:
对每条提示,计算猜测和密码的xAyB值,并与提示结果对比。
关键逻辑:

位操作:
使用poss数组记录每个位置可能的数字集合。
通过按位与和按位取反,动态更新可能的数字集合。
DFS递归:
遍历可能的数字集合,逐个尝试生成密码,并进行验证。

const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
const io = [];
rl.on('line', ln => io.push(ln)).on('close', main);

function main() {
    const [n, ...data] = io; // 读取输入的提示数量和提示内容
    console.log(solve(data.map(x => x.split(' ')))); // 解析提示并求解
}

function solve(hints) {
    // 初始化每个位置可能的数字集合,初始为0-9全部可能
    let poss = Array(4).fill((1 << 10) - 1);

    // 根据提示更新可能性数组
    for (let [g, r] of hints) {
        let [a, b] = r.split('A'); // 提取结果的xA和yB
        b = b[0]; // 只需要y的值

        if (a == '0') { // 如果提示xA为0
            for (let i = 0; i < 4; i++) {
                if (b == '0') {
                    // 如果yB为0,数字在该位置不可能出现
                    poss[i] &= ~(1 << +g[i]);
                } else {
                    // 否则,该数字可能出现在其他位置,但不能同时占多个位置
                    poss[i] &= ~(1 << +g[i]) | (1 << 10);
                }
            }
        }
    }

    // 用于存储符合条件的候选密码
    let res = [];
    // 开始DFS搜索符合条件的密码
    dfs(0, [], poss, hints, res);

    // 如果只有一个符合条件的密码,返回该密码;否则返回"NA"
    return res.length === 1 ? res[0].join('') : 'NA';
}

// 深度优先搜索,生成密码组合并验证其有效性
function dfs(idx, curr, poss, hints, res) {
    if (idx === 4) { // 如果已生成4位密码
        if (isValid(curr, hints)) res.push([...curr]); // 验证密码是否有效
        return;
    }
    for (let i = 0; i < 10; i++) {
        if (poss[idx] & (1 << i)) { // 检查当前位置是否可能为数字i
            curr.push(i); // 将数字i加入当前密码组合
            dfs(idx + 1, curr, poss, hints, res); // 递归处理下一位
            curr.pop(); // 回溯,移除当前数字
        }
    }
}

// 验证当前密码是否满足所有提示
function isValid(guess, hints) {
    for (let [g, r] of hints) {
        let [a, b] = calcAB(guess, g.split('').map(Number)); // 计算实际的xA和yB
        if (a != r[0] || b != r[2]) return false; // 如果不匹配,返回false
    }
    return true; // 所有提示均匹配,返回true
}

// 计算猜测和答案的xA和yB值
function calcAB(ans, guess) {
    let a = 0, b = 0;
    let m1 = Array(10).fill(0), m2 = Array(10).fill(0);

    // 遍历4位数字
    for (let i = 0; i < 4; i++) {
        if (ans[i] === guess[i]) {
            a++; // 数字和位置都正确,增加xA
        } else {
            m1[ans[i]]++; // 记录答案中的数字
            m2[guess[i]]++; // 记录猜测中的数字
        }
    }

    // 计算yB:取每个数字出现次数的最小值
    for (let i = 0; i < 10; i++) b += Math.min(m1[i], m2[i]);

    return [a, b]; // 返回xA和yB
}

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏


http://www.kler.cn/a/503515.html

相关文章:

  • MMDetection框架下的常见目标检测与分割模型综述与实践指南
  • Ubuntu中双击自动运行shell脚本
  • 贪心算法详细讲解(沉淀中)
  • nginx负载均衡-基于端口的负载均衡(一)
  • OpenCV相机标定与3D重建(51)对 3x3 矩阵进行 RQ 分解(RQ Decomposition)函数RQDecomp3x3()的使用
  • 一 rk3568 Android 11固件开发环境搭建 (docker)
  • 代码随想录算法训练营第十二天|第18题. 四数之和
  • golang之数据库操作
  • ctf竞赛
  • VirtualBox环境中vscode报错:提取扩展时出错。Failed to fetch
  • Steam个人开发者注册备记
  • 解锁未来情感科技:AI 机器人 Ropet 搭载的前沿智能黑科技
  • K8s数据存储之详解(Detailed Explanation of K8s Data Storage)
  • 【JVM-2.2】使用JConsole监控和管理Java应用程序:从入门到精通
  • latex 中不要求显示页码
  • (一)QSQLite3库简介
  • 平台介绍-快速开发上手指南
  • 快速、可靠且高性价比的定制IP模式提升芯片设计公司竞争力
  • MCANet: 基于多模态字幕感知的大语言模型训练无关视频异常检测
  • 【向量数据库 Milvus】centos8源码安装和部署 Milvus 2.5.3
  • 惯性动作捕捉设备制作动画:打破传统动画制作模式,提高动画制作效率
  • Python 标准库:time——时间的访问和转换
  • MySQL社区版下载及其环境配置(msi)
  • 嵌入式Linux之基于TCP协议的程序
  • 配置Allure环境变量【macOS版】
  • 麒麟系统设置tomcat开机自启动