华为od机试题 真题
以下题目附带Java解法,是我个人写的,不一定是标准答案,没有真正的测试数据,只能说是我自己认为通过率100%,也不一定是最优解。如果有错误或是有更好的解法,请评论告诉我!!!
58.处理所有作业总时长
一个工厂有m条流水线
来并行完成n个独立的作业
该工厂设置了一个调度系统
在安排作业时,总是优先执行处理时间最短的作业
现给定流水线个数m
需要完成的作业数n
每个作业的处理时间分别为 t1,t2...tn
请你编程计算处理完所有作业的耗时为多少
当n>m时 首先处理时间短的m个作业进入流水线
其他的等待
当某个作业完成时,
依次从剩余作业中取处理时间最短的
进入处理
输入描述:
第一行为两个整数(采取空格分隔)
分别表示流水线个数m和作业数n
第二行输入n个整数(采取空格分隔)
表示每个作业的处理时长 t1,t2...tn
0<m,n<100
0<t1,t2...tn<100
输出描述
输出处理完所有作业的总时长
案例
输入
3 5
8 4 3 2 10
输出
13
说明
先安排时间为2,3,4的三个作业
第一条流水线先完成作业
调度剩余时间最短的作业8
第二条流水线完成作业
调度剩余时间最短的作业10
总共耗时 就是二条流水线完成作业时间13(3+10)
输入
3 9
1 1 1 2 3 4 6 7 8
输出
13
// 处理所有作业的总时长
// 解题思路:对数组进行排序,累加每条流水线分配的任务的时长,输出最大的
public static void test058() {
Scanner sc = new Scanner(System.in);
String line1 = sc.nextLine();
String line2 = sc.nextLine();
String[] split1 = line1.split(" ");
// 流水线个数m和作业数n
int m = Integer.parseInt(split1[0]);
int n = Integer.parseInt(split1[1]);
String[] split2 = line2.split(" ");
List<Integer> list = new ArrayList<>();
for (int i = 0; i < split2.length; i++) {
list.add(Integer.parseInt(split2[i]));
}
// 对数组进行排序
Collections.sort(list);
// 作业数n小于等于流水线个数m,则结果为排序后的最后一个值
if (n <= m) {
System.out.println(list.get(list.size() - 1));
return;
}
// 结果
int res = 0;
// 遍历每一条流水线
for (int k = 0; k < m; k++) {
// 每条流水线获取到的任务时长总和
int allTime = 0;
// 累加每条流水线获取到的任务时长
for (int i = k; i < list.size(); i += m) {
allTime += list.get(i);
}
// 取最大的
res = Math.max(allTime, res);
}
System.out.println(res);
}
53.最大停车距离
停车场有一横排车位0代表没有停车,1代表有车.
至少停了一辆车在车位上,也至少有一个空位没有停车.
为防止刮蹭,需为停车人找到一个车位
使得停车人的车最近的车辆的距离是最大的
返回此时的最大距离
输入描述:
1. 一个用半角逗号分割的停车标识字符串,停车标识为0或1,
0为空位,1为已停车
2. 停车位最多有100个
输出描述
1. 输出一个整数记录最大距离
示例一:
输入
1,0,0,0,0,1,0,0,1,0,1
输出
2
说明
当车停在第三个位置上时,离其最近的车距离为2(1~3)
当车停在第四个位置上时,离其最近的车距离为2(4~6)
其他位置距离为1
因此最大距离为2
// 最大停车距离
// 解题思路:取出所有已停车的位置的索引,计算其与停车场头的距离、停车场尾的距离、两车之间的距离/2,输出最大的值
public static void test053(){
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
String[] split = line.split(",");
// 存放停车位置的索引
List<Integer> list = new ArrayList<>();
for (int i = 0; i < split.length; i++) {
int num = Integer.parseInt(split[i]);
if (1 == num) {
list.add(i);
}
}
// 第一辆车与停车场头的距离
int startLen = list.get(0);
// 最后一辆车与停车场尾的距离
int endLen = split.length - 1 - list.get(list.size() - 1);
int res = 0;
for (int i = 0; i < list.size() - 1; i++) {
// 停车后与左右车的最小距离
int len = (list.get(i + 1) - list.get(i)) / 2;
res = Math.max(res, len);
}
// 最大距离
System.out.println(Math.max(res,Math.max(startLen, endLen)));
}
52.磁盘容量排序
磁盘的容量单位有M,G,T这三个等级
他们之间的换算关系为
1T=1024G
1G=1024M
现在给定N块磁盘的容量
请对他们按从小到大的顺序进行稳定排序
例如给定5块盘容量
1T,20M,3G,10G6T,3M12G9M
排序后的结果为20M,3G,3M12G9M,1T,10G6T
注意单位可以重复出现
上述3M12G9M为 3M+12G+9M和 12M12G相等
输入描述:
输入第一行包含一个整数N
2<=N<=100 ,表示磁盘的个数
接下来的N行每行一个字符串 长度 (2<l<30)
表示磁盘的容量
有一个或多个格式为 mv的子串组成
其中m表示容量大小 v表示容量单位
例如
磁盘容量m的范围 1~1024正整数
容量单位v的范围包含题目中提到的M,G,T
输出描述:
输出N行
表示N块磁盘容量排序后的结果
示例1:
输入
3
1G
2G
1024M
输出
1G
1024M
2G
说明 1G和1024M容量相等,稳定排序要求保留他们原来的相对位置
故1G在1024M前
示例二:
输入
3
2G4M
3M2G
1T
输出
3M2G
2G4M
1T
说明1T大于2G4M大于3M2G
// 磁盘容量排序
// 解题思路:将输入的值放在集合中,将每个元素都转换为M为单位,在进行比较排序
public static void test052_2() {
Scanner sc = new Scanner(System.in);
int len = Integer.parseInt(sc.nextLine());
List<String> list = new ArrayList<>();
for (int i = 0; i < len; i++) {
list.add(sc.nextLine());
}
list.sort((s1, s2) -> {
// 复杂的写法,使用双层循环分别求出每个数字和字母
char[] chars1 = s1.toCharArray();
char[] chars2 = s2.toCharArray();
// 使用long型防止int型不够用
long allNum1 = 0;
long allNum2 = 0;
for (int i = 0; i < chars1.length; i++) {
String num = "";
// 判断是否是数字->获得字母前的数字
while (i < chars1.length && Character.isDigit(chars1[i])) {
// 拼接数字
num = num + chars1[i];
i++;
}
if (chars1[i] == 'M') {
allNum1 += Integer.parseInt(num);
} else if (chars1[i] == 'G') {
allNum1 += Integer.parseInt(num) * 1024;
} else {
allNum1 += Integer.parseInt(num) * 1024 * 1024;
}
}
for (int i = 0; i < chars2.length; i++) {
String num = "";
// 判断是否是数字->获得字母前的数字
while (i < chars2.length && Character.isDigit(chars2[i])) {
// 拼接数字
num = num + chars2[i];
i++;
}
if (chars2[i] == 'M') {
allNum2 += Integer.parseInt(num);
} else if (chars2[i] == 'G') {
allNum2 += Integer.parseInt(num) * 1024;
} else {
allNum2 += Integer.parseInt(num) * 1024 * 1024;
}
}
// 比较两个long型数据,x > y 返回1,x < y返回-1,x = y返回0
return Long.compare(allNum1, allNum2);
});
for (String s : list) {
System.out.println(s);
}
}
// 巧妙的解法
public static void test052() {
Scanner sc = new Scanner(System.in);
int len = Integer.parseInt(sc.nextLine());
List<String> list = new ArrayList<>();
for (int i = 0; i < len; i++) {
list.add(sc.nextLine());
}
// 对数组进行排序
list.sort((s1, s2) -> {
long num1 = toNumber(s1);
long num2 = toNumber(s2);
// 比较两个long型数据,x > y 返回1,x < y返回-1,x = y返回0
return Long.compare(num1, num2);
});
for (String s : list) {
System.out.println(s);
}
}
/**
* 将字符串转为具体多少M,返回一个long型数字
*
* @return
*/
private static long toNumber(String s) {
// 正则表达式:根据字母M或G或T进行分割
String[] numArray = s.split("[M|G|T]"); // 结果[1,2,3]
// 正则表达式:根据1个或多个数字进行分割
String[] letterArray = s.split("[0-9]+"); // 结果[,M,T,G] 因为字符串以数字开头,所以数组第一个是空
// 返回的结果
long sum = 0;
for (int i = 1; i < letterArray.length; i++) {
String letter = letterArray[i];
long num = Long.parseLong(numArray[i - 1]);
if ("M".equals(letter)) {
sum += num;
} else if ("G".equals(letter)) {
sum += 1024 * num;
} else if ("T".equals(letter)) {
sum += 1024 * 1024 * num;
}
}
return sum;
}
51.非严格递增连续数字序列长度
输入一个字符串仅包含大小写字母和数字
求字符串中包含的最长的非严格递增连续数字序列长度
比如:
12234属于非严格递增数字序列
示例:
输入
abc2234019A334bc
输出
4
说明:
2234为最长的非严格递增连续数字序列,所以长度为4
输入
aaaaaa44ko543j123j7345677781
输出
8
输入
aaaaa34567778a44ko543j123j71
输出
8
输入
345678a44ko543j123j7134567778aa
输出
9
输入
fwefksoSKJF12S45DS3DSAJKSldsf565441345sd1f87151234657812154341543
输出
5
// 非严格递增连续数字序列长度
// 解题思路:遍历每一个字符,按照规则计算非严格递增连续数字序列长度,保留最大长度
public static void test051() {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
char[] chars = line.toCharArray();
// 当前非严格递增长度
int currentLen = 0;
// 非严格递增最大长度
int maxLen = 0;
// 上一个字符,默认一个比数字大的
char last = 'a';
for (char c : chars) {
if (Character.isDigit(c)) { // 当前字符是数字
if (currentLen == 0) { // 当数字是开头时
currentLen++;
} else if (c >= last) { // 符合非严格递增,当前非严格递增长度长度
currentLen++;
} else { // 不符合非严格递增,保留最大的非严格递增长度
maxLen = Math.max(currentLen, maxLen);
// 初始化当前严格递增长度,因为当前是数字,所以其本身长度是1
currentLen = 1;
}
// 将当前数字置为上一个,用于比较
last = c;
} else { // 当前字符不是数字
// 保留最大的非严格递增长度
maxLen = Math.max(maxLen, currentLen);
// 初始化当前严格递增长度
currentLen = 0;
}
}
System.out.println(maxLen);
}
50.均分糖果
小明从糖果盒中随意抓一把糖果
每次小明会取出一半的糖果分给同学们
当糖果不能平均分配时
小明可以从糖果盒中(假设盒中糖果足够)取出一个或放回一个糖果
小明至少需要多少次(取出放回和平均分配均记一次)能将手中糖果分至只剩一颗
输入描述:
抓取糖果数(小于1000000):15
输出描述:
最少分至一颗糖果的次数:5
示例1:
输入
15
输出
5
备注
解释:(1) 15+1=16;
(2) 16/2=8;
(3) 8/2=4;
(4) 4/2=2;
(5) 2/2=1;
// 这道题通过率好像只有85%,我也不知道原因
// 均分糖果
// 解题思路:当糖果数n不是偶数时,当(n + 1) / 2 % 2 == 0 说明num+1后除以2还是偶数,所以选择n+1,否则n-1
public static void test050() {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
int count = 0;
while (num != 1) {
// 当num=3时,不符合一下规则,但是很容易算出是2次,所以直接加2并结束
if (num == 3) {
System.out.println(count + 2);
return;
}
// 当num不是偶数
if (num % 2 != 0) {
// 当(num + 1) / 2 % 2 == 0 说明num+1后除以2还是偶数,所以选择+1,否则-1
if ((num + 1) / 2 % 2 == 0) {
num++;
} else {
num--;
}
// 无论是+1还是-1,count都要累加1
count++;
} else { // 当nums是偶数,除以2,count累加1
num /= 2;
count++;
}
}
System.out.println(count);
}
48.没有相同字符的元素长度乘积的最大值
给定一个元素类型为小写字符串的数组
请计算两个没有相同字符的元素长度乘积的最大值
如果没有符合条件的两个元素返回0
输入描述
输入为一个半角逗号分割的小写字符串数组
2<= 数组长度 <=100
0< 字符串长度 <=50
输出描述
两个没有相同字符的元素长度乘积的最大值
示例一
输入
iwdvpbn,hk,iuop,iikd,kadgpf
输出
14
说明
数组中有5个元组 第一个和第二个元素没有相同字符
满足条件 输出7*2=14
// 没有相同字符的元素长度乘积的最大值
// 解题思路:一一比对元素,看一个元素是否包含另一个元素,如果没有则保留这两个元素的长度的乘积,保留最大的
public static void test048() {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
String[] split = line.split(",");
int sum = 0;
for (int i = 0; i < split.length; i++) {
for (int j = i + 1; j < split.length; j++) {
// 两个元素有没有相同字符标识位
boolean flag = true;
String first = split[i];
String next = split[j];
// 遍历一个元素的全部字符
for (int k = 0; k < first.length(); k++) {
// 判断是否包含这些字符
if (next.contains(first.charAt(k) + "")) {
// 有相同的字符
flag = false;
break;
}
}
// 没有相同的字符
if (flag) {
// 计算两个元素长度的乘积,保留最大的
sum = Math.max(sum, first.length() * next.length());
}
}
}
System.out.println(sum);
}
47. 相对开音节结构的子串个数
相对开音节构成的结构为辅音+元音(aeiou)+辅音(r除外)+e
常见的单词有bike cake
给定一个字符串,以空格为分隔符
反转每个单词的字母
若单词中包含如数字等其他非字母时不进行反转
反转后计算其中含有相对开音节结构的子串个数
(连续子串中部分字符可以重复)
输入描述
字符串 以空格分割的多个单词
长度<10000 字母只考虑小写
输出描述
含有相对开音节结构的子串个数
示例1:
输入
ekam a ekac
输出
2
说明:
反转后为 make a cake 其中make和cake为相对开音节子串
返回2
示例2:
输入
!ekam a ekekac
输出
2
说明
反转后为 !ekam a cakeke
因为!ekam含有非英文字母,所以未反转
其中 cake和keke 为相对开音节子串 返回2
// 疑问:不进行反转的单词要不要算相对开音节子串?我这里是算的,如果不算的话,则将反转后的单词单独放到集合里,在进行处理
// 相对开音节结构的子串个数
// 解题思路:遍历所有单词,根据条件进行反转,反转后在计算相对开音节结构的子串个数
public static void test047() {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
String[] split = line.split(" ");
// 相对开音节结构的子串个数
int count = 0;
for (int i = 0; i < split.length; i++) {
String str = split[i];
// 若单词中包含如数字等其他非字母时不进行反转
if (str.replaceAll("[a-z]", "").length() == 0) {
String newStr = "";
for (int j = 0; j < str.length(); j++) {
newStr = str.charAt(j) + newStr;
}
str = newStr;
}
// 计算相对开音节结构的子串个数
for (int k = 0; k < str.length() - 3; k++) {
// 辅音+元音(aeiou)+辅音(r除外)+e
if (!"aeiou".contains(str.charAt(k) + "")
&& "aeiou".contains(str.charAt(k + 1) + "")
&& !"aeiour".contains(str.charAt(k + 2) + "")
&& 'e' == str.charAt(k + 3)) {
count++;
}
}
}
System.out.println(count);
}
46.火星人公式求值
已知火星人使用的运算符号为#;$
其与地球人的等价公式如下
x#y=2*x+3*y+4
x$y=3*x+y+2
x y是无符号整数
地球人公式按照c语言规则进行计算
火星人公式中$符优先级高于# 相同的运算符按从左到右的顺序运算
输入描述:
火星人字符串表达式结尾不带回车换行
输入的字符串说明是 字符串为仅有无符号整数和操作符组成的计算表达式
1.用例保证字符串中操作数与操作符之间没有任何分隔符
2.用例保证操作数取值范围为32位无符号整数,
3.保证输入以及计算结果不会出现整型溢出
4.保证输入的字符串为合法的求值报文
例如: 123#4$5#76$78
5.保证不会出现非法的求值报文
例如: #4$5 这种缺少操作数
4$5# 这种缺少操作数
4#$5 这种缺少操作数
4 $5 有空格
3+4-5*6/7 有其他操作符
12345678987654321$54321 32位整数溢出
输出描述:
根据火星人字符串输出计算结果
结尾不带回车换行
案例1:
输入:
7#6$5#12
输出:
226
说明 示例7#6$5#12=7#(3*6+5+2)#12
=7#25#12
=(2*7+3*25+4)#12
=93#12
=2*93+3*12+4
=226
// 火星人公式求值
// 解题思路:根据数字、#$ 将字符串分割成两个数组,先计算$,在计算#
public static void test046() {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
String[] sign = line.split("[0-9]+"); // { ,#,$,$}
List<String> signList = new ArrayList<>();
// 数字前面是空串,所以从1开始
for (int i = 1; i < sign.length; i++) {
signList.add(sign[i]);
}
String[] nums = line.split("[$|#]+"); // {1,2,23,34}
List<Integer> numsList = new ArrayList();
for (int i = 0; i < nums.length; i++) {
numsList.add(Integer.parseInt(nums[i]));
}
// 找出所有的$
while (signList.indexOf("$") != -1) {
int index$ = signList.indexOf("$");
// 计算$表达式
int sum = calculation$(numsList.get(index$), numsList.get(index$ + 1));
// 替换 $前后的数字 为 $表达式的值
numsList.set(index$, sum);
numsList.remove(index$ + 1);
// 移除$符号
signList.remove(index$);
}
// 计算#表达式的值
int res = numsList.get(0);
for (int i = 1; i < numsList.size(); i++) {
res = calculation(res, numsList.get(i));
}
System.out.println(res);
}
/**
* x$y=3*x+y+2
* @param num1
* @param num2
* @return
*/
private static int calculation$(int num1, int num2) {
return 3 * num1 + num2 + 2;
}
/**
* x#y=2*x+3*y+4
* @param num1
* @param num2
* @return
*/
private static int calculation(int num1, int num2) {
return 2 * num1 + 3 * num2 + 4;
}