【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试之【回溯】2023C-加密算法【欧弟算法】全网注释最详细分类最全的华为OD真题题解

有LeetCode算法/华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1336了解算法冲刺训练

文章目录

  • 题目描述与示例
    • 题目描述
    • 输入描述
    • 输出描述
    • 示例一
      • 输入
      • 输出
    • 示例二
      • 输入
      • 输出
  • 解题思路
  • 代码
    • python
    • Java
    • C++
    • 时空复杂度
  • 华为OD算法/大厂面试高频题算法练习冲刺训练

题目描述与示例

题目描述

有一种特殊的加密算法,明文为一段数字串,经过密码本查找转换,生成另一段密文数字串。规则如下

  1. 明文为一段数字串由0-9组成
  2. 密码本为数字0-9组成的二维数组
  3. 需要按明文串的数字顺序在密码本里找到同样的数字串,密码本里的数字串是由相邻的单元格数字组成,上下和左右是相邻的,注意:对角线不相邻,同一个单元格的数字不能重复使用。
  4. 每一位明文对应密文即为密码本中找到的单元格所在的行和列序号(序号从0开始)组成的两个数字。如明文第iData[i]对应密码本单元格为Book[X][Y],则明文第i位对应的密文为X YXY之间用空格隔开。如果有多条密文,返回字符序最小的密文。如果密码本无法匹配,返回"error".

请你设计这个加密程序。

示例 1:

密码本:

{0,0,2},
{1,3,4},
{6,6,4}

明文"3",密文"1 1"

示例 2:

密码本:

{0,0,2},
{1,3,4},
{6,6,4}

明文"0 3",密文"0 1 1 1"

示例 3:

密码本:

{0,0,2,4}
{1,3,4,6}
{3,4,1,5}
{6,6,6,5}

明文"0 0 2 4",密文"0 0 0 1 0 2 0 3""0 0 0 1 0 2 1 2",返回字典序小的"0 0 0 1 0 2 0 3"

输入描述

第一行输入1个正整数N,代表明文的长度(1 <= N <= 9)

第二行输入N个明文数字组成的序列Data[i](整数,0 <= Data[i] <= 9)

第三行输入1个正整数M,(1 <= M <= 9)

接下来输入一个M*M的矩阵代表密码本Book[i][i],(整数,0 <= Book[i][i] <= 9)

输出描述

如明文 第iData[i]对应密码本单元格为Book[i][j],则明文第i位对应的密文为X YXY之间用空格隔开。如果有多条密文,返回字符序最小的密文。如果密码本无法匹配,返回"error"

示例一

输入

2
0 3
3
0 0 2
1 3 4
6 6 4

输出

0 1 1 1

示例二

输入

4
0 0 2 4
4
0 0 2 4
1 3 4 6
3 4 1 5
6 6 6 5

输出

0 0 0 1 0 2 0 3

解题思路

注意,本题和LeetCode79. 单词搜索、【回溯】2023C-找到它非常类似。唯一的区别是,题目不保证答案是唯一的,当存在多个合适的密文的时候,需要返回字典序最小的那个。

本题基本思路和【回溯】2023C-找到它一致。本题需要着重考虑最小字典序的问题。

这个时候,搜索的方向数组DIRECTIONS里的顺序就非常重要了。假设当前点为(x, y),那么其近邻点为

  • 上方:(x-1, y)
  • 左方:(x, y-1)
  • 右方:(x, y+1)
  • 下方:(x+1, y)

显然,如果存在多个近邻点同时满足下一个字符的时候,按照上、左、右、下这个顺序来搜索的话,一定能够得到最小的字典序,因为坐标为更小字典序的近邻点被优先搜索了

这也是极少数的,我们需要特别注意方向数组DIRECTIONS的顺序的题目。即

DIRECTIONS = [(-1, 0), (0, -1), (0, 1), (1, 0)]

代码

python

# 题目:2023C-加密算法
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:回溯
# 代码看不懂的地方,请直接在群上提问# 全局的方向数组,表示上下左右移动四个方向
# 【特别注意】:此处的顺序是非常重要的,必须按照【上、左、右、下】来排布
# 这样才能使得计算得到的密文一定是字典序最小
DIRECTIONS = [(-1, 0), (0, -1), (0, 1), (1, 0)]# 构建回溯函数,各个参数的含义为
# grid:         原二维矩阵
# M:            原二维矩阵的大小M
# check_list:   大小和grid一样的检查列表,用于判断某个点是否已经检查过
# x,y:          当前在grid中的点的坐标
# s:            待搜索的明文
# s_idx:        待搜索的明文此时遍历到的索引位置
# path:         当前路径
def backtracking(grid, M, check_list, x, y, s, s_idx, path):# 声明全局变量isFindglobal isFind# 如果在之前的回溯中已经找到了最小字典序的密文,直接返回if isFind:return# 若此时s_idx等于s的长度-1,即N-1# 说明s中的所有数字都在grid中找到了# 修改isFind为True,输出答案,同时终止递归if s_idx == N - 1:isFind = Trueprint(" ".join(f"{item[0]} {item[1]}" for item in path))return# 遍历四个方向,获得点(x,y)的近邻点(nx,ny)for dx, dy in DIRECTIONS:nx, ny = x+dx, y+dy# (nx,ny)必须满足以下三个条件,才可以继续进行回溯函数的递归调用# 1. 不越界;2. 尚未检查过;# 3.在grid中的值grid[nx][ny]为s的下一个字符s[s_idx+1]if 0 <= nx < M and 0 <= ny < M and check_list[nx][ny] == False and grid[nx][ny] == s[s_idx+1]:# 状态更新:将点(nx,ny)在check_list中的状态更新为True,更新path末尾check_list[nx][ny] = Truepath.append((nx, ny))# 回溯:将点(nx,ny)传入回溯函数中,注意此时s_idx需要+1backtracking(grid, M, check_list, nx, ny, s, s_idx+1, path)# 回滚:将点(nx,ny)在check_list中的状态重新修改回False,将path末尾的函数弹出check_list[nx][ny] = Falsepath.pop()# 输入明文长度N
N = int(input())
# 输入待查找的明文
s = input().split()
# 输入密码本的行数列数M
M = int(input())
# 构建密码本二维网格
grid = list()
for _ in range(M):grid.append(input().split())# 构建全局变量isFind,初始化为False
isFind = False# 构建大小和grid一样的检查数组check_list
# 用于避免出现重复检查的情况
check_list = [[False] * M for _ in range(M)]
# 双重遍历整个二维网格grid
for i in range(M):for j in range(M):# 找到点(i,j)等于s的第一个数字# 则点(i,j)可以作为递归的起始位置if grid[i][j] == s[0]:# 将点(i,j)在check_list中设置为已检查过check_list[i][j] = True# 回溯函数递归入口,path初始为储存点(i,j)backtracking(grid, M, check_list, i, j, s, 0, [(i, j)])# 将点(i,j)在check_list中重置为未检查过,因为本次回溯不一定找到答案check_list[i][j] = False# 如果在回溯中,全局变量isFind被改为True,说明找到了明文,直接退出循环if isFind:break# 关于i的循环同理,找到明文之后直接退出循环if isFind:break# 如果最终没找到明文,输出error
if not isFind:print("error")

Java

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;public class Main {// 全局的方向数组,表示上下左右移动四个方向// 【特别注意】:此处的顺序是非常重要的,必须按照【上、左、右、下】来排布// 这样才能使得计算得到的密文一定是字典序最小static final int[][] DIRECTIONS = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};static boolean isFind = false;// 构建回溯函数static void backtracking(String[][] grid, int M, boolean[][] checkList, int x, int y, String[] s, int sIdx, List<List<Integer>> path) {// 如果在之前的回溯中已经找到了最小字典序的密文,直接返回if (isFind) return;// 若此时sIdx等于s的长度-1,即N-1// 说明s中的所有数字都在grid中找到了// 修改isFind为True,输出答案,同时终止递归if (sIdx == s.length - 1) {isFind = true;StringBuilder sb = new StringBuilder();for (List<Integer> point : path) {sb.append(point.get(0)).append(" ").append(point.get(1)).append(" ");}System.out.println(sb);return;}// 遍历四个方向,获得点(x,y)的近邻点(nx,ny)for (int[] dir : DIRECTIONS) {int nx = x + dir[0];int ny = y + dir[1];// (nx,ny)必须满足以下三个条件,才可以继续进行回溯函数的递归调用// 1. 不越界;2. 尚未检查过;// 3.在grid中的值grid[nx][ny]为s的下一个字符s[sIdx+1]if (nx >= 0 && nx < M && ny >= 0 && ny < M && !checkList[nx][ny] && grid[nx][ny].equals(s[sIdx + 1])) {// 状态更新:将点(nx,ny)在checkList中的状态更新为True,更新path末尾checkList[nx][ny] = true;List<Integer> point = new ArrayList<>();point.add(nx);point.add(ny);path.add(point);// 回溯:将点(nx,ny)传入回溯函数中,注意此时sIdx需要+1backtracking(grid, M, checkList, nx, ny, s, sIdx + 1, path);// 回滚:将点(nx,ny)在checkList中的状态重新修改回False,将path末尾的点弹出checkList[nx][ny] = false;path.remove(path.size() - 1);}}}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int N = scanner.nextInt();String[] s = new String[N];for (int i = 0; i < N; i++) {s[i] = scanner.next();}int M = scanner.nextInt();String[][] grid = new String[M][M];for (int i = 0; i < M; i++) {for (int j = 0; j < M; j++) {grid[i][j] = scanner.next();}}// 构建大小和grid一样的检查数组checkList// 用于避免出现重复检查的情况boolean[][] checkList = new boolean[M][M];// 双重遍历整个二维网格gridfor (int i = 0; i < M; i++) {for (int j = 0; j < M; j++) {// 找到点(i,j)等于s的第一个数字// 则点(i,j)可以作为递归的起始位置if (grid[i][j].equals(s[0])) {// 将点(i,j)在checkList中设置为已检查过checkList[i][j] = true;List<List<Integer>> path = new ArrayList<>();List<Integer> point = new ArrayList<>();point.add(i);point.add(j);path.add(point);// 回溯函数递归入口,path初始为储存点(i,j)backtracking(grid, M, checkList, i, j, s, 0, path);// 将点(i,j)在checkList中重置为未检查过,因为本次回溯不一定找到答案checkList[i][j] = false;// 如果在回溯中,全局变量isFind被改为True,说明找到了明文,直接退出循环if (isFind) {break;}}}// 关于i的循环同理,找到明文之后直接退出循环if (isFind) {break;}}// 如果最终没找到明文,输出errorif (!isFind) {System.out.println("error");}}
}

C++

#include <iostream>
#include <vector>
#include <string>using namespace std;// 全局的方向数组,表示上下左右移动四个方向
// 【特别注意】:此处的顺序是非常重要的,必须按照【上、左、右、下】来排布
// 这样才能使得计算得到的密文一定是字典序最小
const vector<vector<int>> DIRECTIONS = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
bool isFind = false;// 构建回溯函数
void backtracking(vector<vector<string>>& grid, int M, vector<vector<bool>>& checkList, int x, int y, vector<string>& s, int sIdx, vector<vector<int>>& path) {// 如果在之前的回溯中已经找到了最小字典序的密文,直接返回if (isFind) return;// 若此时sIdx等于s的长度-1,即N-1// 说明s中的所有数字都在grid中找到了// 修改isFind为True,输出答案,同时终止递归if (sIdx == s.size() - 1) {isFind = true;for (int i = 0; i < path.size(); ++i) {cout << path[i][0] << " " << path[i][1] << " ";}cout << endl;return;}// 遍历四个方向,获得点(x,y)的近邻点(nx,ny)for (auto& dir : DIRECTIONS) {int nx = x + dir[0];int ny = y + dir[1];// (nx,ny)必须满足以下三个条件,才可以继续进行回溯函数的递归调用// 1. 不越界;2. 尚未检查过;// 3.在grid中的值grid[nx][ny]为s的下一个字符s[sIdx+1]if (nx >= 0 && nx < M && ny >= 0 && ny < M && !checkList[nx][ny] && grid[nx][ny] == s[sIdx + 1]) {// 状态更新:将点(nx,ny)在checkList中的状态更新为True,更新path末尾checkList[nx][ny] = true;path.push_back({nx, ny});// 回溯:将点(nx,ny)传入回溯函数中,注意此时sIdx需要+1backtracking(grid, M, checkList, nx, ny, s, sIdx + 1, path);// 回滚:将点(nx,ny)在checkList中的状态重新修改回False,将path末尾的点弹出checkList[nx][ny] = false;path.pop_back();}}
}int main() {int N;cin >> N;vector<string> s(N);for (int i = 0; i < N; ++i) {cin >> s[i];}int M;cin >> M;vector<vector<string>> grid(M, vector<string>(M));for (int i = 0; i < M; ++i) {for (int j = 0; j < M; ++j) {cin >> grid[i][j];}}// 构建大小和grid一样的检查数组checkList// 用于避免出现重复检查的情况vector<vector<bool>> checkList(M, vector<bool>(M, false));// 双重遍历整个二维网格gridfor (int i = 0; i < M; ++i) {for (int j = 0; j < M; ++j) {// 找到点(i,j)等于s的第一个数字// 则点(i,j)可以作为递归的起始位置if (grid[i][j] == s[0]) {// 将点(i,j)在checkList中设置为已检查过checkList[i][j] = true;vector<vector<int>> path = {{i, j}};// 回溯函数递归入口,path初始为储存点(i,j)backtracking(grid, M, checkList, i, j, s, 0, path);// 将点(i,j)在checkList中重置为未检查过,因为本次回溯不一定找到答案checkList[i][j] = false;// 如果在回溯中,全局变量isFind被改为True,说明找到了明文,直接退出循环if (isFind) {break;}}}// 关于i的循环同理,找到明文之后直接退出循环if (isFind) {break;}}// 如果最终没找到明文,输出errorif (!isFind) {cout << "error" << endl;}return 0;
}

时空复杂度

时间复杂度:O(M^2*3^N)。其中N为密文s的长度,这是一个比较宽松的上界,回溯过程中每一个点都最多有三个分支可以进入。

空间复杂度:O(M^2)check_list所占空间。


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/809033.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从 Oracle 到 MySQL 数据库的迁移之旅

文章目录 引言一、前期准备工作1.搭建新的MySQL数据库2 .建立相应的数据表2.1 数据库兼容性分析2.1.1 字段类型兼容性分析2.1.2 函数兼容性分析2.1.3 是否使用存储过程&#xff1f;存储过程的个数&#xff1f;复杂度&#xff1f;2.1.4 是否使用触发器&#xff1f;个数&#xff…

Paper Reading: MixTeacher:半监督目标检测中利用混合尺度教师挖掘有前景的标签

目录 简介目标/动机工作重点方法训练 实验总结 简介 题目&#xff1a;《MixTeacher: Mining Promising Labels with Mixed Scale Teacher for Semi-Supervised Object Detection》&#xff0c; CVPR 2023 日期&#xff1a;2023.3.16 单位&#xff1a;腾讯&#xff0c;上海交…

竞赛 图像识别-人脸识别与疲劳检测 - python opencv

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是…

Android MVVM架构学习——ViewModel DataBinding

关于MVVM架构&#xff0c;我并不想花篇幅去做重复性的描述&#xff0c;网上一搜都是一堆讲解&#xff0c;大家可以自行了解&#xff0c;我所做的只是以最简单的例子&#xff0c;最有效的步骤&#xff0c;从零开始&#xff0c;去实现一个相对有点学习参考价值的项目。 先来看本…

安卓开发LinearLayout的属性极其用法

线性布局&#xff08;LinearLayout&#xff09;是 Android 开发中常用的布局之一&#xff0c;它可以按照水平&#xff08;horizontal&#xff09;或垂直&#xff08;vertical&#xff09;方向排列子视图。以下是线性布局的一些常用属性和用法&#xff1a; 1. **android:orient…

计算机网络——NAT技术

目录 前言 前篇 引言 SNAT&#xff08;Source Network Address Translation&#xff09;源网络地址转换 SNAT流程 确定性标记 DNAT&#xff08;Destination Network Address Translation&#xff0c;目标网络地址转换&#xff09; NAT技术重要性 前言 本博客是博主用于…

windows10下Linux子系统(ubuntu22.04)安装docker(二进制)和kubectl

下载安装docker wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.6.tgz tar xf docker-20.10.6.tgz chown -R root.root docker cp docker/* /usr/bin/ groupadd docker mkdir /var/lib/docker /etc/docker配置文件 vim /etc/docker/daemon.json …

无人新零售引领的创新浪潮

无人新零售引领的创新浪潮 在数字化时代加速演进的背景下&#xff0c;无人新零售作为商业领域的一股新兴力量&#xff0c;正以其独特的高效性和便捷性重塑着传统的购物模式&#xff0c;开辟了一条充满创新潜力的发展道路。 依托人脸识别、物联网等尖端技术&#xff0c;无人新…

【JavaScript】大文件分片

第一步&#xff1a;先对整个文件进行md5&#xff0c;根据文件内容生成hash&#xff1b; 第二步&#xff1a;给每一个分块命名&#xff1a;${hash}_${i}.${suffix}&#xff0c;这样每一块都带有整个文件的hash&#xff0c;并将所有分块进行收集为数组partList中&#xff1b;后端…

Redis中的集群(七)

集群 ASK错误 ASKING命令 ASKING命令唯一要做的就是打开发送该命令的客户端的REDIS_ASKING标识&#xff0c;以下是该命令的伪代码实现: def ASKING(): # 打开标识 client.flags | REDIS_ASKING# 向客户端返回OK回复 reply("OK")在一般情况下&#xff0c;如果客户…

搜维尔科技:【煤矿安全仿真】煤矿事故预防处置VR系统,矿山顶板灾害,冲击地压灾害等预防演练!

产品概述 煤矿事故预防处置VR系统 系统内容&#xff1a; 事故预防处置VR系统的内容包括&#xff1a;火灾的预防措施、火灾预兆、防灭火系统、火灾案例重现、顶板事故预兆、顶板事故原因、顶板事故案例重现、瓦斯概念及性质、瓦斯的涌出形式、瓦斯预兆、瓦斯爆炸条件及预防措…

数据结构之排序了如指掌(一)

目录 题外话 正题 排序概念 稳定性 直接插入排序 直接插入排序代码详解 直接插入排序复杂度分析 希尔排序(缩小增量排序) 希尔排序代码详解 小结 题外话 昨晚肚子疼没睡好,今天博客写的确实有点晚(找个借口),我一定会坚持,不辜负热爱我的家人们!! 正题 排序概念 一串…

苍穹外卖jwt令牌p10

点击小虫&#xff08;进入断点调试&#xff09;&#xff0c;打上断点&#xff0c;然后前端点击登录&#xff08;此时前端的数据会作为参数传入&#xff09;&#xff1a; 光标放在字段上还会显示接收到的数据&#xff1a; 若想程序在所希望的地方停止&#xff0c;可以添加断点&a…

《战神4》和《战神5》有什么联系吗 苹果电脑如何运行《战神4》苹果电脑玩战神 Mac玩游戏 战神5攻略 crossover激活码

《战神4》&#xff08;God of War 2018&#xff09;和《战神5》&#xff08;God of War: Ragnark&#xff09;是一对引人注目的游戏作品&#xff0c;它们不仅在游戏界引起了广泛的关注&#xff0c;也给玩家带来了深入探索北欧神话世界的机会。这两部游戏之间的联系不仅体现在剧…

【力扣】101. 对称二叉树

101. 对称二叉树 题目描述 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 提示…

JavaWeb开发01--Maven-Web入门-请求响应-分层解耦

一、Maven 1.maven概述 Apache Maven是一个项目管理和构建工具&#xff0c;它基于项目对象模型(POM)的概念&#xff0c;通过一小段描述信息来管理项目的构建。 根据提供的插件实现很多功能 maven的作用 管理和构建java项目的工具 依赖管理&#xff1a;可以直接在pom.xml文件…

app 创建快捷入口 在手机上面多个icon

activity-alias详解及应用-CSDN博客 Android动态修改应用图标最佳实践 - 简书 AndroidManifest.xml 中 <activity-aliasandroid:name"包名.ui.mine.SecondActivityAlias"android:label"快捷入口"android:icon"mipmap/collection_one"andro…

深入理解MD5算法:原理、应用与安全

title: 深入理解MD5算法&#xff1a;原理、应用与安全 date: 2024/4/11 20:55:57 updated: 2024/4/11 20:55:57 tags: MD5算法数据安全哈希函数摘要算法安全漏洞SHA算法密码学 第一章&#xff1a;引言 导言 在当今数字化时代&#xff0c;数据安全和完整性变得至关重要。消息…

【Leetcode每日一题】 动态规划 - 下降路径最小和(难度⭐⭐)(55)

1. 题目解析 题目链接&#xff1a;931. 下降路径最小和 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了. 2.算法原理 对于这类路径类问题&#xff0c;通常我们首先需要分析状态表示以及状态转移的过程。特别地&#xff0c;本题涉及…

The C programming language (second edition,KR) exercise(CHAPTER 3)

E x c e r c i s e 3 − 1 Excercise\quad 3-1 Excercise3−1&#xff1a;输出结果如图1所示&#xff0c;这里故意让二分搜索算法去寻找一个在数组中不存在在的数&#xff0c;然后去看两种二分搜索算法分别所花费的时间的大小&#xff0c;为了使得所花费的时间更具有可分辨性&a…