概述
华为od机试题 真题
- 45.满足规则的数组组合
- 44.最长连续子序列的和等于输入值
- 43.整数编码
- 42.输出指定格式字符
- 40.小朋友分班
- 39.数列解析
- 38. url拼接
- 36.满足最低能力值的数量
以下题目附带Java解法,是我个人写的,不一定是标准答案,没有真正的测试数据,只能说是我自己认为通过率100%,也不一定是最优解。如果有错误或是有更好的解法,请评论告诉我!!!
45.满足规则的数组组合
给定一个正整数数组
检查数组中是否存在满足规则的数组组合
规则:
A=B+2C
输入描述
第一行输出数组的元素个数
接下来一行输出所有数组元素 用空格隔开
输出描述
如果存在满足要求的数
在同一行里依次输出 规则里 A/B/C的取值 用空格隔开
如果不存在输出0
示例1:
输入
4
2 7 3 0
输出
7 3 2
说明:
7=3+2*2
示例2:
输入
3
1 1 1
输出
0
说明找不到满足条件的组合
备注:
数组长度在3~100之间
数组成员为0~65535
数组成员可以重复
但每个成员只能在结果算式中使用一次
如 数组成员为 [0,0,1,5]
0出现两次允许,但结果0=0+2*0不允许 因为算式中使用了3个0
用例保证每组数字里最多只有一组符合要求的解
// 满足规则的数组组合
// 解题思路:对输入的数字进行排序,a从后往前取,取最大的,b、c取比a小的,且b!=c
public static void test045(){
Scanner sc = new Scanner(System.in);
int len = Integer.parseInt(sc.nextLine());
String line = sc.nextLine();
String[] split = line.split(" ");
List<Integer> list = new ArrayList<>();
for (int i = 0; i < len; i++) {
list.add(Integer.parseInt(split[i]));
}
// 对list进行排序
Collections.sort(list);
// 三重循环,虽然效率低,但是简单
for (int a = len - 1; a >= 0; a--) {
// A的值肯定是大于等于B、C的,所以B、C的取值范围要在a前
for (int b = 0; b < a; b++) {
// c!=b 是因为每个成员只能在结果算式中使用一次
for (int c = 0; c < a && c != b; c++) {
if (list.get(a) == list.get(b) + 2*list.get(c)) {
System.out.println(list.get(a) + " " + list.get(b) + " " + list.get(c));
return;
}
}
}
}
System.out.println(0);
}
44.最长连续子序列的和等于输入值
有N个正整数组成的一个序列
给定一个整数sum
求长度最长的的连续子序列使他们的和等于sum
返回次子序列的长度
如果没有满足要求的序列 返回-1
案例1:
输入
1,2,3,4,2
6
输出
3
解析:1,2,3和4,2两个序列均能满足要求
所以最长的连续序列为1,2,3 因此结果为3
示例2:
输入
1,2,3,4,2
20
输出
-1
解释:没有满足要求的子序列,返回-1
备注: 输入序列仅由数字和英文逗号构成
数字之间采用英文逗号分割
序列长度 1<=N<=200
输入序列不考虑异常情况
由题目保证输入序列满足要求
// 最长连续子序列的和等于输入值
// 解题思路:双层循环,第一层遍历每一个数字,第二层往后累加,记录符合条件的长度,保留最大长度
public static void test044(){
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
int num = Integer.parseInt(sc.nextLine());
String[] split = line.split(",");
int count = -1;
for (int i = 0; i < split.length; i++) {
// 连续子串累加值
int sum = 0;
// 记录起始位置
int j = i;
// 子循环,寻找符合条件的子串
while (j < split.length) {
sum += Integer.parseInt(split[j]);
// 小于目标值,则向后走一位
if (sum < num) {
j++;
} else if (sum == num) { // 等于目标值,记录长度,只保留最大值
count = Math.max(count, j - i + 1);
} else { // 超出目标值,退出子循环,从下个数开始
break;
}
}
}
System.out.println(count);
}
43.整数编码
实现一个整数编码方法
使得待编码的数字越小
编码后所占用的字节数越小
编码规则如下
1.编码时7位一组,每个字节的低7位用于存储待编码数字的补码
2.字节的最高位表示后续是否还有字节,置1表示后面还有更多的字节,
置0表示当前字节为最后一个字节
3.采用小端序编码,低位和低字节放在低地址上
4.编码结果按16进制数的字符格式进行输出,小写字母需要转化为大写字母
输入描述
输入的为一个字符串表示的非负整数
输出描述
输出一个字符串表示整数编码的16进制码流
示例一
输入
0
输出
00
说明:输出的16进制字符不足两位的前面补零
示例二
输入
100
输出
64
说明:100的二进制表示为0110 0100只需一个字节进行编码
字节的最高位0,剩余7位存储数字100的低7位(1100100)所以编码后的输出为64
示例三
输入
1000
输出
E807
说明
1000的二进制表示为 0011 1110 1000 至少需要两个字节进行编码
第一个字节最高位是1 剩余7位存储数字 1000的低7位(1101000)
所以第一个字节的二进制位(1110 1000)即E8
第二个字节最高位置0 剩余的7位存储数字 1000的第二个低7位(0000111)
所以第一个字节的二进制为(0000 0111)即07
采用小端序编码 所以低字节E8输出在前面
高字节07输出在后面
备注
代编码数字取值范围为 [0,1<<64-1]
// 整数编码
// 解题思路:将输入的数转为二进制数,从后往前依次截取7位,根据要求拼接0或1,在把每个结果拼接起来
// 小端序编码 大概意思就是原来低位放在高位,高位放在低位,就是颠倒过来。在这里的意思就是低位转的放在前面,越高位转的放在越后面(可能理解有误)
// 代码通过率没有100%,自己的测试数据都能过,暂不知道原因,能看出异常的请告诉我!!!
public static void test043() {
Scanner sc = new Scanner(System.in);
int input = sc.nextInt();
// 将输入的数字转为二进制
String binaryValue = Integer.toBinaryString(input);
int len = binaryValue.length();
if (len <= 7) {
int parseInt = Integer.parseInt("0" + binaryValue, 2);
System.out.println(tenTo16(parseInt));
return;
}
int count = len / 7;
// 存放结果
String res = "";
for (int i = 0; i < count; i++) {
// 存储每7位的十进制数
int num = 0;
// 从后往前截取7位
String lastStr = binaryValue.substring(len - 7 * (i + 1), len - 7 * i);
// 前几位
if (i == count - 1) {
// len % 7 == 0 说明没有了,所以补0
if (len % 7 == 0) {
// 拼接0
num = Integer.parseInt("0" + lastStr, 2);
} else {
// 拼接1
num = Integer.parseInt("1" + lastStr, 2);
}
} else { // 其他的补1
// 拼接1
num = Integer.parseInt("1" + lastStr, 2);
}
// 小端序
res = res + tenTo16(num);
}
// 取最前的几位
if (len % 7 != 0) {
int numTen = Integer.parseInt(binaryValue.substring(0, len - 7 * count), 2);
String s = tenTo16(numTen);
res = res + s;
}
System.out.println(res);
}
/**
* 十进制转十六进制
*
* @return
*/
private static String tenTo16(int num) {
String s = "";
do {
int res = num % 16;
num = num / 16;
if (res == 15) {
s = "F" + s;
} else if (res == 14) {
s = "E" + s;
} else if (res == 13) {
s = "D" + s;
} else if (res == 12) {
s = "C" + s;
} else if (res == 11) {
s = "B" + s;
} else if (res == 10) {
s = "A" + s;
} else {
s = res + s;
}
} while (num != 0);
if (s.length() == 1) {
return "0" + s;
}
return s;
}
/**
* 任何进制转10进制
* 十进制转二进制
* 十进制转十六进制
*/
public void study() {
// 任何进制数转10进制,第一个参数:要转的字符串; 第二个参数:要转的字符串的进制数
int parseInt = Integer.parseInt("110", 2);
// 十进制转二进制
String s = Integer.toBinaryString(123);
// 十进制转十六进制,十六进制的字母是小写的
String s1 = Integer.toHexString(123);
// 字符串小写字母转大写
String upperCase = s1.toUpperCase();
// 字符串大写字母转小写
String lowerCase = s1.toLowerCase();
}
42.输出指定格式字符
Vlan是一种为局域网设备进行逻辑划分的技术
为了标识不同的vlan 引入了vlan id 1~4094之间的整数
定义一个vlan id 的资源池
资源池中连续的vlan用开始vlan-结束vlan表示,
不连续的用单个整数表示
所有的vlan用英文逗号连接起来
现有一个vlan资源池,业务需要从资源池中申请一个vlan
需要你输出从vlan资源池中移除申请的vlan后的资源池
输入描述
第一行为字符串格式的vlan资源池
第二行为业务要申请的vlan vlan的取值范围1~4094
输出描述
从输入vlan资源池中移除申请的vlan后
字符串格式的vlan资源池
输出要求满足题目中要求的格式,
并且要求从小到大升序输出
如果申请的vlan不在原资源池,输出升序排序的原资源池的字符串即可
示例一
输入
1-5
2
输出
1,3-5
说明:原vlan资源池中有1 2 3 4 5 移除2后
剩下的1 3 4 5按照升序排列的方式为 1 3-5
示例二
输入
20-21,15,18,30,5-10
15
输出
5-10,18,20-21,30
说明:
原vlan资源池中有5 6 7 8 9 10 15 18 20 21 30
移除15后 剩下的为 5 6 7 8 9 10 18 20 21 30
按照题目描述格式并升序后的结果为5-10,18,20-21,30
示例三
输入
5,1-3
10
输出
1-3,5
资源池中有1 2 3 5
申请的资源不在资源池中
将原池升序输出为1-3,5
输入池中vlan数量范围为2~2094的整数
资源池中vlan不重复且合法1~2094的整数
输入是乱序的
// 输出指定格式字符
// 解题思路:用一个集合,存储每一个拆开后的每一个数字,移除目标数字后进行排序,遍历集合,组装连续的数字
public static void test042() {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
int num = sc.nextInt();
// 将输入的字符串根据,分割成数组
String[] split = line.split(",");
List<Integer> list = new ArrayList<>();
// 遍历数组
for (int i = 0; i < split.length; i++) {
String str = split[i];
// 将数组每一个字符拆成数组存进新集合中
if (str.contains("-")) {
String[] split1 = str.split("-");
int start = Integer.parseInt(split1[0]);
int end = Integer.parseInt(split1[1]);
for (int j = start; j <= end; j++) {
list.add(j);
}
} else {
list.add(Integer.parseInt(str));
}
}
// 移除目标数字
list.remove((Integer) num);
// 对数组进行排序
Collections.sort(list);
// 存放结果
StringBuilder sb = new StringBuilder();
// 遍历集合,组装连续的数字
for (int i = 0; i < list.size(); i++) {
int start = i;
while (i + 1 < list.size() && list.get(i) + 1 == list.get(i + 1)) {
i++;
}
// 单个数字
if (start == i) {
sb.append(list.get(start) + ",");
} else { // 连续的数字
sb.append(list.get(start) + "-" + list.get(i) + ",");
}
}
System.out.println(sb.substring(0, sb.length() - 1));
}
40.小朋友分班
幼儿园两个班的小朋友排队时混在了一起
每个小朋友都知道自己跟前面一个小朋友是不是同班
请你帮忙把同班的小朋友找出来
小朋友的编号为整数
与前面一个小朋友同班用Y表示
不同班用N表示
输入描述:
输入为空格分开的小朋友编号和是否同班标志
比如 6/N 2/Y 3/N 4/Y
表示一共有4位小朋友
2和6是同班 3和2不同班 4和3同班
小朋友总数不超过999
0< 每个小朋友编号 <999
不考虑输入格式错误
输出两行
每一行记录一班小朋友的编号 编号用空格分开
并且
1. 编号需要按照大小升序排列,分班记录中第一个编号小的排在第一行
2. 如果只有一个班的小朋友 第二行为空
3. 如果输入不符合要求输出字符串ERROR
示例:
输入
1/N 2/Y 3/N 4/Y
输出
1 2
3 4
说明:2的同班标记为Y因此和1同班
3的同班标记位N因此和1,2不同班
4的同班标记位Y因此和3同班
// 小朋友分班
// 解题思路:用一个LinkedHashMap存储小朋友编号和Y/N,遍历map,用两个集合存放不同班的小朋友,判断小朋友应该加入哪个list
public static void test040() {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
// map key存储每一个小朋友的编号,value存储N/Y。用LinkedHashMap是因为它是有序的,按插入顺序排序
Map<Integer, String> map = new LinkedHashMap<>();
try {
String[] split = line.split(" ");
for (int i = 0; i < split.length; i++) {
String str = split[i];
String[] split1 = str.split("/");
// 第一个小朋友必须是N
if (i == 0 && "Y".equals(split1[1])) {
System.out.println("ERROR");
return;
}
// 不是N/Y,或重复出现,报错
if (!("N".equals(split1[1]) || "Y".equals(split1[1])) || map.containsKey(Integer.parseInt(split1[0]))) {
System.out.println("ERROR");
return;
}
map.put(Integer.parseInt(split1[0]), split1[1]);
}
// 用两个list存储两个班的小朋友
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
// 先存第一个小朋友
list1.add(Integer.parseInt(line.substring(0, line.indexOf("/"))));
// 从map中移除第一个小朋友
map.remove(Integer.parseInt(line.substring(0, line.indexOf("/"))), "N");
// 用来判断小朋友应该加入哪个list
boolean flag = true;
// 遍历map,当flag=true,key=Y时,加入list1;key=N时,加入list2,且flag=false。当flag=false,key=Y时,加入list2;key=N时,加入list1,且flag=true。
for (Integer s : map.keySet()) {
if (flag) {
if ("Y".equals(map.get(s))) {
list1.add(s);
} else {
list2.add(s);
flag = false;
}
} else {
if ("Y".equals(map.get(s))) {
list2.add(s);
} else {
list1.add(s);
flag = true;
}
}
}
// 对list进行排序
Collections.sort(list1);
Collections.sort(list2);
for (int k = 0; k < list1.size(); k++) {
System.out.print(list1.get(k) + " ");
}
System.out.println();
for (int k = 0; k < list2.size(); k++) {
System.out.print(list2.get(k) + " ");
}
} catch (Exception e) {
System.out.println("ERROR");
return;
}
}
39.数列解析
有一个数列A[n]
从A[0]开始每一项都是一个数字
数列中A[n+1]都是A[n]的描述
其中A[0]=1
规则如下
A[0]:1
A[1]:11 含义其中A[0]=1是1个1 即11
表示A[0]从左到右连续出现了1次1
A[2]:21 含义其中A[1]=11是2个1 即21
表示A[1]从左到右连续出现了2次1
A[3]:1211 含义其中A[2]从左到右是由一个2和一个1组成 即1211
表示A[2]从左到右连续出现了一次2又连续出现了一次1
A[4]:111221 含义A[3]=1211 从左到右是由一个1和一个2两个1 即111221
表示A[3]从左到右连续出现了一次1又连续出现了一次2又连续出现了2次1
输出第n项的结果
0<= n <=59
输入描述:
数列第n项 0<= n <=59
4
输出描述
数列内容
111221
// 数列解析
// 解题思路:根据A[0]循环求出A[1]、A[2]....
public static void test039() {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
if (num == 0) {
System.out.println(1);
return;
}
// 初始值A[0]
String s = "1";
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= num; i++) {
char[] chars = s.toCharArray();
// 遍历字符串的每个字符
for (int j = 0; j < chars.length; j++) {
int start = j;
// 相同字符
while (j + 1 < chars.length && chars[j] == chars[j + 1]) {
j++;
}
// 只有一个
if (start == j) {
sb.append(1).append(chars[j]);
} else { // 有多个
sb.append(j - start + 1).append(chars[j]);
}
}
// 替换初始值
s = sb.toString();
// 置空
sb = new StringBuilder();
}
System.out.println(s);
}
38. url拼接
给定一个url前缀和url后缀
通过,分割 需要将其连接为一个完整的url
如果前缀结尾和后缀开头都没有/
需要自动补上/连接符
如果前缀结尾和后缀开头都为/
需要自动去重
约束:
不用考虑前后缀URL不合法情况
输入描述
url前缀(一个长度小于100的字符串)
url后缀(一个长度小于100的字符串)
输出描述
拼接后的url
一、
输入
/acm,/bb
输出
/acm/bb
二、
输入
/abc/,/bcd
输出
/abc/bcd
三、
输入
/acd,bef
输出
/acd/bef
四、
输入
,
输出
/
// url拼接
public static void test038() {
Scanner in = new Scanner(System.in);
String line = in.nextLine();
in.close();
String[] split = line.split(",");
if (split.length == 0) {
System.out.println("/");
return;
}
String combine = split[0] + "/" + split[1];
// 如果出现多个/,则替换成/
String url = combine.replaceAll("/+", "/");
System.out.println(url);
}
36.满足最低能力值的数量
用数组代表每个人的能力
一个比赛活动要求 参赛团队的最低能力值为N
每个团队可以由一人或者两人组成
且一个人只能参加一个团队
计算出最多可以派出多少只符合要求的队伍
输入描述
5
3 1 5 7 9
8
第一行代表总人数,范围 1~500000
第二行数组代表每个人的能力
数组大小范围 1~500000
元素取值范围 1~500000
第三行数值为团队要求的最低能力值
1~500000
输出描述
3
最多可以派出的团队数量
示例一
输入
5
3 1 5 7 9
8
输出
3
说明 3、5组成一队 1、7一队 9自己一队 输出3
7
3 1 5 7 9 2 6
8
输出
4
3
1 1 9
8
输出
1
// 满足最低能力值的数量
// 解题思路:遍历输入的数组,记录大于N的值的数量,将小于N的放进集合里,对集合进行排序,采用双指针,筛选大于N的组合
public static void test036() {
Scanner sc = new Scanner(System.in);
int len = Integer.parseInt(sc.nextLine());
String[] split = sc.nextLine().split(" ");
int requireValue = Integer.parseInt(sc.nextLine());
List<Integer> list = new ArrayList<>();
// 大于N的值的数量
int count = 0;
for (int i = 0; i < len; i++) {
int num = Integer.parseInt(split[i]);
if (num >= requireValue) {
count++;
} else {
list.add(num);
}
}
// 对集合进行排序
Collections.sort(list);
// 双指针
// 头指针:集合头
int start = 0;
// 尾指针:数组尾
int end = list.size() - 1;
while (start < end) {
// 当头尾指针之和满足要求,count++,头指针向前移动一步,尾指针向后移动一步
if (list.get(start) + list.get(end) >= requireValue) {
count++;
start++;
end--;
} else { // 当头尾指针之和不满足要求,头指针向前移动一步,尾指针不变
start++;
}
}
System.out.println(count);
}
更多华为od机试题请点这里<华为od机试题6 真题>,每篇8题,有更多的题也请告诉我啊
最后
以上就是高兴万宝路为你收集整理的华为od机试题5 真题的全部内容,希望文章能够帮你解决华为od机试题5 真题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复