注意事项

本文包括社招题库中的较简单题目,如华为OD中分值为100的题目

模拟

空间占用计算

题目描述

员工A的磁盘空间经常被耗尽,他需要找到占用空间最大的目录或文件,然后决定如何清理文件释放空间。

给定某一目录,请写那些程序帮他统计目录内一级子目录和文件的占用空间,并返回目标目录一级子项(文件或子目录)中占用空间最大的项。

规则说明

  1. 目录占用空间为其内部所有文件 Size 的总和,目录本身 Size 为0
  2. 目录深度不高于 7,目录或文件名总长度不超过 128 字节
  3. 当存在多个子项占用空间均为最大时,多个子项采用字符升序排列。
  4. 目标目录不再文件系统中时(输入路径前缀匹配不到任何路径),返回空列表。

输入描述

输入要统计的目标目录

文件系统内的文件列表

文件 Size 列表,该列表中的数据和文件列表存在一一对应关系。

输出描述

目标目录一级子项(文件或子目录)中占用空间最大的项组成的列表。

用例 1:

1
2
3
4
5
6
7
输入:
/dir1/dir2-1
/dir0/dir1-1/file1-1 /dir1/dir1-1/file1-1 /dir1/dir2-1/file3-1 /dir1/dir2-1/file3-2 /dir1/dir2-1/file3-3
8192 81920 2048 8192 1024

输出:
file3-2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package a_medium;

import java.util.*;

// https://blog.csdn.net/qq_45776114/article/details/159804170
// 空间占用计算
public class a01_space_occupation_calculation {


// 目录节点
static class Node {
Map<String, Node> childrenDir = new HashMap<>();
Map<String, Node> childrenFile = new HashMap<>();
String name;
int size = 0;
}

// DFS 计算目录大小
static int dfs(Node root) {
int sum = 0;

// 子目录
for (Node node : root.childrenDir.values()) {
sum += dfs(node);
}

// 文件
for (Node node : root.childrenFile.values()) {
sum += node.size;
}

root.size = sum;
return sum;
}

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

String path = sc.nextLine();
String file = sc.nextLine();
String fileSize = sc.nextLine();

String[] fileList = file.split(" ");
String[] sizeArr = fileSize.split(" ");

Node root = new Node();

// 构建目录树
for (int i = 0; i < fileList.length; i++) {
String[] parts = fileList[i].split("/");
Node cur = root;

// "/a/b/c.txt".split("/") → ["", "a", "b", "c.txt"]
// 所以j从1开始
for (int j = 1; j < parts.length; j++) {
String name = parts[j];
boolean isFile = (j == parts.length - 1);

// 如果不是最后一个文件,即c.txt,就是路径
if (!isFile) {
cur.childrenDir.putIfAbsent(name, new Node());
cur.childrenDir.get(name).name = name;
cur = cur.childrenDir.get(name);
} else {
// 文件
Node fileNode = new Node();
fileNode.name = name;
fileNode.size = Integer.parseInt(sizeArr[i]);
cur.childrenFile.put(name, fileNode);
}
}
}

// 找目标目录
Node cur = root;
String[] parts = path.split("/");

for (int i = 1; i < parts.length; i++) {
if (!cur.childrenDir.containsKey(parts[i])) {
return;
}
cur = cur.childrenDir.get(parts[i]);
}

// 修改每个文件节点的size字段
dfs(cur);

List<Node> list = new ArrayList<>();
list.addAll(cur.childrenDir.values());
list.addAll(cur.childrenFile.values());

if (list.isEmpty()) return;

// 排序,默认是降序排序,如果大小相同要按字典序排序
list.sort((a, b) -> {
if (a.size == b.size) return a.name.compareTo(b.name);
return b.size - a.size;
});

int max = list.get(0).size;

for (Node node : list) {
if (node.size != max) break;
// 根据大小输出名字
System.out.print(node.name + " ");
}
}

}

注意

这道题的核心就是模拟。 它模拟了文件系统的目录结构:

  • 用树形结构模拟目录和文件的层级关系
  • 模拟了”构建目录 → 查找目标路径 → 计算大小 → 排序输出”的完整流程

计算数列位置N的值

题目描述

  1. 输入 M,N 两个数,则按照以下规则形成一个数列。
  2. 数列的前 M 个元素的值为 1 到 M
  3. 从 M+1 个元素开始,计算逻辑为
    1. 如果其前 M 个元素中,存在值相同的元素,则该位置上的数值等于前 M 个数中最大数值与最小数值之和。
    2. 如果其前 M 个元素中,不存在值相同的元素,则该位置上的数值等于前 M 个数中最大的数值和最小数值之差。
      请计算该数列第 N 个位置上的数值

补充

  • 3 <= M <= 10
  • 1 <= N <= 50

输入描述

输出N和M,使用 , 分割

输出描述

输出N位置上的数值

用例1

1
2
3
4
5
输入:
5,1

输出:
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package a_medium;

import java.util.*;

// https://blog.csdn.net/qq_45776114/article/details/159804285
// 计算数列位置N的值
public class a02_calculate_the_value_at_position_N {

public static int positionValue(int m, int n) {
// 小于情况就是n
if (n <= m) {
return n;
}

int[] num = new int[n + 1];

// 初始化
for (int i = 1; i <= m; i++) {
num[i] = i;
}

// 数据量小->递推
for (int i = m + 1; i <= n; i++) {
int mx = Integer.MIN_VALUE, mn = Integer.MAX_VALUE;
HashSet<Integer> set = new HashSet<>();
boolean dupFlag = false;

// 检查前 m 个元素
for (int j = i - m; j < i; j++) {
if (set.contains(num[j])) {
// 重复标志
dupFlag = true;
}
set.add(num[j]);

mx = Math.max(mx, num[j]);
mn = Math.min(mn, num[j]);
}

if (dupFlag) {
num[i] = mx + mn;
} else {
num[i] = mx - mn;
}
}

return num[n];
}

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
String[] parts = input.split(",");

int m = Integer.parseInt(parts[0]);
int n = Integer.parseInt(parts[1]);

System.out.println(positionValue(m, n));
}
}

准备生日礼物

题目描述
小明在一个充满人文关怀的公司上班,公司每个月都要为该月生日的同事送一份生日小礼物,该事项由小明负责,请帮助小明统计某一月份应该准备多少礼物,重复录入的员工生日以最后一次录入结果为准,请不要重复统计,避免浪费。

输入描述
参数 1,要发放礼物的月份,取值 1 到 12。
参数 2,员工列表。
参数 3,员工生日日期列表,该列表和员工列表中的数据对应存在一一对应关系,长度一致。

输出描述
该月份要准备的礼品个数。

补充说明

  1. 小明公司的员工人数不超过 100 人。
  2. 员工姓名是字母和数字的组合,姓名长度大于 0,小于 16 字节。
  3. 日期录入格式统一采用 Year/Month/Day , Year 长度为 4, Month和 Day 长度为 1 到 2,系统保证录入日期为合法日期。
  4. 不考虑同名多位员工的情况,名字一致即可认为是同一员工(在生产系统会通过工号区分,本系统简化处理)。

用例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
输入:
5
Alice Bob Charlie David Eve Frank Grace Helen
1985/5/10 1990/10/11 1995/10/11 2000/11/10 2005/05/01 2010/10/13 2015/10/14 2020/5/2

输出:
3

```java
package a_medium;

import java.util.*;

// https://blog.csdn.net/qq_45776114/article/details/159973125
// 准备生日礼物
public class a03_prepare_a_birthday_gift {


public static int calGiftNum(int month, String[] names, String[] birthdays) {
Map<String, Integer> nameMonth = new HashMap<>();

for (int i = 0; i < names.length; i++) {
String currentName = names[i];
String currentBirthday = birthdays[i];
// 生日格式:xxxx/xx/xx,取月份
// Integer.parseInt("05") 和 Integer.parseInt("5") 都会返回整数 5。
int m = Integer.parseInt(currentBirthday.split("/")[1]);
nameMonth.put(currentName, m);
}

// 统计
int count = 0;
for (int m : nameMonth.values()) {
if (m == month) {
count++;
}
}
return count;
}

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

int month = sc.nextInt();
// nextInt() 不消费换行符,nextLine() 会消费换行符。两者混用时,需要手动加一个 nextLine() 来过渡。
sc.nextLine(); // 吃掉换行

String name = sc.nextLine();
String birthday = sc.nextLine();

String[] names = name.split(" ");
String[] birthdays = birthday.split(" ");

int res = calGiftNum(month, names, birthdays);
System.out.println(res);
}


}

配置操作失败数量统计

题目描述
模拟一个系统的命令行配置,包含添加、修改、删除三项操作,详情如下:

  • 添加操作命令:add_rule rule_id=1 rule_index=18
  • 修改操作命令:mod_rule rule_id=1 rule_index=100
  • 删除操作命令:del_rule rule_id=1

其中:add_rulemod_ruledel_rule 是操作关键字,rule_idrule_index是属性关键字且属性取值范围为数字 1 - 9999 之间,操作、属性之间都用空格进行分割。

  1. 在进行所有操作时,如果缺少关键字,或者相应的 rule_idrule_index 的取值不符合要求,则操作失败。
  2. 在进行添加操作时,参数必须包含 rule_idrule_index,如果当前不存在,则添加成功,如果添加已经存在的 rule_id,则操作失败。
  3. 在进行修改操作时,参数必须包含 rule_idrule_index,如果当前 rule_id 不存在,或前后 rule_index 没有变化,则操作失败。
  4. 在进行删除操作时,参数必须包含 rule_id,如果当前 rule_id 不存在,则操作失败。

在进行批量操作时,一个命令失败后可以继续下一条命令的操作。现给有一组批量操作的字符串,包括不超过 1000 条连续的操作指令,格式为 [cmd][cmd][cmd],请将字符串解析后按照顺序进入你实现的系统,统计出配置失败的次数。

输入描述
输入命令以空格分割

输出描述
输出失败命令数量

用例1

1
2
3
4
5
6
7
8
9
10
输入:
add_rule rule_id=1 rule_index=9999
mod_rule rule_id=1 rule_index=10
del_rule rule_id=1

输出:
0

说明:
所有操作都成功。

用例2

1
2
3
4
5
6
7
8
9
10
输入:
add_rule rule_id=1
mod_rule rule_id=1 rule_index=10
del_rule rule_id=1

输出:
0

说明:
add操作不包含rule_index,添加失败,后续修改和删除操作,无对应rule_id数据,也会失败。

用例3

1
2
3
4
5
6
7
8
输入:
add_rule rule_id=1 rule_index=10000

输出:
1

说明:
rule_index超过范围
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package a_medium;

import java.util.*;

// https://blog.csdn.net/qq_45776114/article/details/159973144
// 配置操作失败数量统计
public class a04_configuration_operation_failure_count_statistics {

// 判断字符串是否为 1~9999 的整数
static boolean judegeNumber(String s) {
if (s.isEmpty()) return false;
for (char c : s.toCharArray()) {
if (!Character.isDigit(c)) return false;
}
int num = Integer.parseInt(s);
return num >= 1 && num <= 9999;
}

// 核心逻辑函数:计算错误命令数量
static int calErrorCmdError(List<String> command) {
int errorCount = 0;
Map<String, String> ruleIndex = new HashMap<>(); // 存储 rule_id -> rule_index

for (String line : command) {
String[] cmd = line.split(" "); // 按空格拆分命令

// 命令长度异常,添加修改命令长度是3,删除命令长度是2
if (cmd.length != 2 && cmd.length != 3) {
errorCount++;
continue;
}

String operatorCmd = cmd[0];

if (operatorCmd.equals("del_rule")) { // 删除规则
if (cmd.length != 2) {
errorCount++;
continue;
}

String[] idPropertys = cmd[1].split("=");
if (idPropertys.length != 2 || !idPropertys[0].equals("rule_id")) {
errorCount++;
continue;
}

String id = idPropertys[1];
// 检查 id 是否有效且存在
if (!judegeNumber(id) || !ruleIndex.containsKey(id)) {
errorCount++;
continue;
}

// 正常删除
ruleIndex.remove(id);

} else if (operatorCmd.equals("mod_rule") || operatorCmd.equals("add_rule")) { // 修改或添加规则
if (cmd.length != 3) {
errorCount++;
continue;
}

String[] idPropertys = cmd[1].split("=");
String[] indexPropertys = cmd[2].split("=");

// 检查格式
if (idPropertys.length != 2 || indexPropertys.length != 2
|| !idPropertys[0].equals("rule_id") || !indexPropertys[0].equals("rule_index")) {
errorCount++;
continue;
}

String id = idPropertys[1];
String index = indexPropertys[1];

// 检查数字范围
if (!judegeNumber(id) || !judegeNumber(index)) {
errorCount++;
continue;
}

if (operatorCmd.equals("mod_rule")) {
// 修改规则:不存在或值没变算错误
if (!ruleIndex.containsKey(id) || ruleIndex.get(id).equals(index)) {
errorCount++;
continue;
}
ruleIndex.put(id, index);
} else {
// 添加规则:已存在算错误
if (ruleIndex.containsKey(id)) {
errorCount++;
continue;
}
ruleIndex.put(id, index);
}

} else {
// 操作关键字不对
errorCount++;
}
}

return errorCount;
}

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<String> cmd = new ArrayList<>();
while (sc.hasNextLine()) {
String line = sc.nextLine();
if (line.isEmpty()) break; // 空行结束输入
cmd.add(line);
}

int errorCount = calErrorCmdError(cmd);
System.out.println(errorCount);
}
}

注意

该题逻辑并不复杂,但是涉及到的异常情况校验很多