可上 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳od1441
了解算法冲刺训练(备注【CSDN】否则不通过)
相关推荐阅读
- 【华为OD机考】2024D+E卷最全真题【完全原创题解 | 详细考点分类 | 不断更新题目】
- 【华为OD笔试】2024D+E卷机考套题汇总【真实反馈,不断更新,限时免费】
- 【华为OD笔试】2024D卷命题规律解读【分析300+场OD笔试考点总结】
从2024年8月14号开始,OD机考全部配置为2024E卷。
注意几个关键点:
- 大部分的题目仍为往期2023A+B+C以及2024D的旧题。注意万变不离其宗,把方法掌握,无论遇到什么题目都可以轻松应对。
- 支持多次提交题目,以最后一次提交为准。可以先做200的再做100的,然后可以反复提交。
- E卷仍然为单机位+屏幕监控的形式进行监考。
- 进入考试界面新加入了这样一段话并且用红字标出,可以看出华子对作弊代考等行为是0容忍的,请各位同学认真学习,不要妄图通过其他违规途径通过考试。
题目描述与示例
给定参数 n
,从 1
到 n
会有 n
个整数 1,2,3,...,n
。这 n
个数字共有n!
种排列,按大小顺序升序列出所有排列情况,并一一标记。当 n = 3
时,所有排列如下:"123","132","213","231","312","321"
。
给定 n
和 k
返回第 k
个排列。
输入
第一行为 n
第二行为 k
n 的范围是 1 ~ 9
k 的范围是 1 ~ n!
输出
输出排列第 k
位置的数字
示例一
输入
3
3
输出
213
示例二
输入
2
2
输出
21
解题思路
这道题本质上是一道排列类型的回溯问题。具体过程和LC46. 全排列几乎完全一致。
注意本题可以进行剪枝操作,即无需计算所有排列,只需要计算前k
个排列即可。
代码
python
# 题目:2024E-第N个排列
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:回溯
# 代码看不懂的地方,请直接在群上提问
# 输入n和k
n = int(input())
k = int(input())
# 用于记录当前已经得到了几个全排列的变量cnt
cnt = 0
ans = ""
usedList = [False] * (n+1)
def dfs(path, usedList, k, n):
# cnt和ans均需要声明为全局变量
global cnt, ans
# 如果path的长度等于n,那么得到了一个全排列
if len(path) == n:
# 已获得的全排列的数目+1
cnt += 1
# 如果已经获得了第k个排列,那么得到了答案
if cnt == k:
ans = "".join([str(num) for num in path])
return
# 如果path的小于n,进行递归
else:
for i in range(1, n+1):
# 如果i尚未使用过,那么可以进行递归
if usedList[i] == False:
# 状态更新:usedList[i]改为True,将i加入当前path
usedList[i] = True
path.append(i)
# 回溯
dfs(path, usedList, k, n)
# 回滚:usedList[i]改为False,将i从当前path中删除
usedList[i] = False
path.pop()
# 这里可以进行剪枝,虽然可以不加,但是尽量加上
# 即如果已经找到了第k个排列,那么无需进行后续的回溯
if cnt == k:
return
# 调用递归函数的入口,最开始path为空列表
dfs([], usedList, k, n)
print(ans)
java
import java.util.Scanner;
public class Main {
// 用于记录当前已经得到了几个全排列的变量cnt
static int cnt = 0;
static String ans = "";
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 输入n和k
int n = scanner.nextInt();
int k = scanner.nextInt();
// 初始化usedList数组,用于记录哪些数字已使用过
boolean[] usedList = new boolean[n + 1];
// 调用递归函数的入口,最开始path为空列表
dfs(new StringBuilder(), usedList, k, n);
System.out.println(ans);
}
// 定义递归回溯函数
public static void dfs(StringBuilder path, boolean[] usedList, int k, int n) {
// 如果path的长度等于n,那么得到了一个全排列
if (path.length() == n) {
// 已获得的全排列的数目+1
cnt++;
// 如果已经获得了第k个排列,那么得到了答案
if (cnt == k) {
ans = path.toString();
}
return;
}
// 如果path小于n,进行递归
for (int i = 1; i <= n; i++) {
// 如果i尚未使用过,那么可以进行递归
if (!usedList[i]) {
// 状态更新:usedList[i]改为True,将i加入当前path
usedList[i] = true;
path.append(i);
// 递归调用
dfs(path, usedList, k, n);
// 回滚:usedList[i]改为False,将i从当前path中删除
usedList[i] = false;
path.deleteCharAt(path.length() - 1);
// 剪枝:如果已经找到了第k个排列,无需进行后续的回溯
if (cnt == k) {
return;
}
}
}
}
}
cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 用于记录当前已经得到了几个全排列的变量cnt
int cnt = 0;
string ans = "";
// 定义递归回溯函数
void dfs(vector<int>& path, vector<bool>& usedList, int k, int n) {
// 如果path的长度等于n,那么得到了一个全排列
if (path.size() == n) {
// 已获得的全排列的数目+1
cnt++;
// 如果已经获得了第k个排列,那么得到了答案
if (cnt == k) {
for (int num : path) {
ans += to_string(num);
}
}
return;
}
// 如果path小于n,进行递归
for (int i = 1; i <= n; i++) {
// 如果i尚未使用过,那么可以进行递归
if (!usedList[i]) {
// 状态更新:usedList[i]改为True,将i加入当前path
usedList[i] = true;
path.push_back(i);
// 递归调用
dfs(path, usedList, k, n);
// 回滚:usedList[i]改为False,将i从当前path中删除
usedList[i] = false;
path.pop_back();
// 剪枝:如果已经找到了第k个排列,无需进行后续的回溯
if (cnt == k) {
return;
}
}
}
}
int main() {
// 输入n和k
int n, k;
cin >> n >> k;
// 初始化usedList数组,用于记录哪些数字已使用过
vector<bool> usedList(n + 1, false);
// 初始化path列表
vector<int> path;
// 调用递归函数的入口,最开始path为空列表
dfs(path, usedList, k, n);
// 输出答案
cout << ans << endl;
return 0;
}
时空复杂度
时间复杂度:O(k)
。需要计算得到前k
种排列。
空间复杂度:O(N)
。usedList
所占空间。
华为OD算法/大厂面试高频题算法练习冲刺训练
-
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!
-
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
-
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
-
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
-
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
-
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
-
绿色聊天软件戳
od1336
了解更多