华为2017校招机试题

1. 同网CS
描述:
小明同学最近新购置了电脑,想和其他同学玩CS,但是建了局域网游戏之后,别人加不进来,自己也进不了别人的主机,非常苦恼。于是来请教同宿舍的“科技怪人”小犀,小犀说了句“你的IP和我们不在同一个子网”就闪了,小明百度了一下,搜到如下关于“子网掩码”的信息:子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。最为简单的理解就是两台计算机各自的IP地址与子网掩码进行AND运算后,如果得出的结果是相同的,则说明这两台计算机是处于同一个子网里面,可以进行直接的通讯。
运算演示之一:
I P 地址  192.168.0.1
子网掩码  255.255.255.0
转化为二进制进行运算:
I P 地址 11010000.10101000.00000000.00000001
子网掩码 11111111.11111111.11111111.00000000
AND运算
     11010000.10101000.00000000.00000000
转化为十进制后为:
      192.168.0.0
运算演示之二:
I P 地址  192.168.0.254
子网掩码  255.255.255.0
转化为二进制进行运算:
I P 地址 11010000.10101000.00000000.11111110
子网掩码 11111111.11111111.11111111.00000000
AND运算
     11010000.10101000.00000000.00000000
转化为十进制后为:
      192.168.0.0
运算演示之三:
I P 地址  192.168.0.4
子网掩码  255.255.255.0
转化为二进制进行运算:
I P 地址 11010000.10101000.00000000.00000100
子网掩码 11111111.11111111.11111111.00000000
AND运算
     11010000.10101000.00000000.00000000
转化为十进制后为:
      192.168.0.0
通过以上对三组计算机IP地址与子网掩码的AND运算后,我们可以看到它运算结果是一样的。均为192.168.0.0
所以计算机就会把这三台计算机视为是同一子网。
小明灵机一动,打算做一个帮助大家解决局域网游戏问题的工具,设想如下:
我知道我的电脑的IP和子网掩码,又知道另外几个同学的ip地址,通过这个工具就可以知道我可以和谁一起CS。
IP寻址规则:
A.网络标识不能数值127开头(在A类地址中127.0.0.1是loopback IP)
B.网络标识第一个字节不能是255和0
C.IP每个字段不能大于255
子网掩码:
A. 不能全部是255;
B. 不能全部是0;
C. 掩码的高位(bit)必须是连续的1; 例如 : 255.255.252.0 --> 11111111.11111111.11111100.00000000 按照Bit来看1和0的位必须是连续的,而掩码高位都是1,所以有时候会见到 错误 : 255.255.253.0 --> 11111111.11111111.11111101.00000000 这里就出现bit为1但没有连续的情况,这种掩码是不正确的
 
运行时间限制: 无限制
内存限制: 无限制
输入:
第一行是我的电脑的IP地址


第二行是我的电脑的子网掩码


第三行整数N,表示后面N个同学的IP地址


第1个同学的IP地址


......


第N个同学的IP地址
输出:
计算并输出N个IP地址是否与我的电脑在同一子网内。


对于在同一子网的输出:let's rock


对于在不同子网的输出:not you


对于无效的联网IP输出:Invalid IP address.


对于无效的子网掩码:Invalid netmask address.
样例输入:
192.168.0.1
255.255.255.0
3
192.168.0.2
192.168.0.200
192.168.2.2
样例输出:
let's rock
let's rock
not you
答案提示:
 参考测试用例:
测试用例1:
输入:
10.123.12.7
255.0.0.0
3
10.121.234.1
192.168.19.9
10.124.123.2
输出:
let's rock
not you
let's rock
测试用例2:
输入:
192.168.29.1
255.255.255.0
2
127.0.0.1
192.168.29.100
输出:
Invalid IP address.
let's rock
测试用例3:
输入:
10.144.240.73
255.252.253.0
输出:
Invalid netmask address.
测试用例4:
输入:
10.144.240.73
0.0.0.0
输出:
Invalid netmask address.
测试用例5:
输入:
10.146.240.256
输出:
Invalid IP address.
测试用例6:
输入:
255.148.240.1
输出:
Invalid IP address.
测试用例7:
输入:
0.147.240.15
输出:

Invalid IP address.

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class IPTest {
	 static String ip0 = "";
	 static String mask = "";
	public static void main(String[] args) {
		 List<String> list = readDataFromConsole();
		 if(list==null){
			 return;
		 }
		 String output="";
		 String org = getNetSeg(ip0, mask);
		 for (int i = 0; i < list.size(); i++) {
			String ip = list.get(i);
			if(!isValidIP(ip)){
				output+="Invalid IP address.\n";
			}else{
				if(getNetSeg(ip, mask).equals(org)){
					output+="let's rock\n";
				}else{
					output+="not you\n";
				}
			}
		}
		System.out.println(output);
		
	}

	private static boolean isValidIP(String ip){
		int[] intArr = string2intArr(ip);
		if(intArr==null||intArr[0]==127||intArr[0]==255||intArr[0]==0){
			return false;
		}
		for (int i = 0; i < intArr.length; i++) {
			if(intArr[i]>255){
				return false;
			}
		}
		return true;
	}

	private static boolean isValidMask(String mask){
		if(string2intArr(mask)==null){
			return false;
		}
		if(mask.equals("255.255.255.255")||mask.equals("0.0.0.0")){
			return false;
		}
		
		if (dec2Binary(mask).split("0").length>1){//如果合法,如111000...,split后数组长度为1
			return false;
		}
		return true;
	}
	private static String dec2Binary(String ip){
		int[] intArr = string2intArr(ip);
		String binStr = "";
		for (int i = 0; i < intArr.length; i++) {
			String tmp = Integer.toBinaryString(intArr[i]);
			tmp = "0000000"+tmp;
			binStr += tmp.substring(tmp.length()-8, tmp.length());//为了使转换后的二进制都为8位
		}
		return binStr;
	}
	private static int[] string2intArr(String ip){
		String[] strArr = ip.split("\\.");
		if (strArr.length!=4){
			return null;
		}
		int[] intArr = new int[4];
		for (int i = 0; i < strArr.length; i++) {
			intArr[i] = Integer.parseInt(strArr[i]);
		}
		return intArr;
	}
	private static String getNetSeg(String ip, String mask){
		int[] ipArr = string2intArr(ip);
		int[] maskArr = string2intArr(mask);
		String res = "";
		for (int i = 0; i < maskArr.length; i++) {
			res+= ipArr[i]& maskArr[i];
		}
		return res;
	}
	private static List<String> readDataFromConsole() {
		Scanner scanner = new Scanner(System.in);
		List<String> ipList = new ArrayList<String>();
		ip0 = scanner.next();
		if(!isValidIP(ip0)){
			 System.out.println("Invalid IP address.");
			 return null;
		 }
		mask = scanner.next();
		if(!isValidMask(mask)){
			 System.out.println("Invalid netmask adress.");
			 return null;
		 }
		int count = scanner.nextInt();
		while (count-->0) {  
           ipList.add(scanner.next()) ;
         } 
		return ipList;
	}
}

分析:这题没什么难点,不过功能点比较多,所以有点耗时间。部分功能有多种实现方法,比如判断子网掩码是否不合法,可以用一个正则表达式“^1.?01.+0$”(以1开头,0结尾,中间有01的)。十进制转二进制也可以自己用除法、取余实现。

 
2. 自动售货系统
描述:考生需要模拟实现一个简单的自动售货系统,实现投币、购买商品、退币、输出库存商品及存钱盒信息的功能.
1. 系统中存在以下商品与钱币:
三种商品:每种商品包含商品名称、单价、数量三种属性,分别为:名称为A1的商品单价为2元数量为5件;名称为A2的商品单价为3元数量为10件;名称为A3的商品单价为4元数量为14件
存钱盒信息存在以下三种面额1、2、5元的钱币,每种钱币包括面额、张数属性,分别为:1元的 5张;2元的 5张, 5元的 3张;
2. 系统退币原则:根据系统存钱盒内钱币的信息,按钱币总张数最少的原则进行退币,即使用户只投币不购买商品也按此原则退币。
3. 约束:考生不需要考虑命令的非法性,即不存在非法的命令的情况,例如系统中A1商品只有5件,不存在买第6件的情况,不存在买的商品总价超过投币总和的等情况。
4. 输入说明
系统接收到输入命令需要初始化系统,初始化系统中商品与钱币数量。命令字与参数间使用一个空格分隔,不同命令之间用逗号分隔。
1). 投币命令:命令格式:p 钱币面额,投币可以投入多次,只能投入1、2、5元面额的钱币。
2). 购买商品:命令格式:b 商品名称
一条购买命令仅能购买一件商品,可以多次购买;购买商品成功后,自动售货机中对应商品数量减1,存钱盒中金额相应的增加,全部购买完成需要按退币原则把多余的钱币退回。
例如:p 5,p 5,p 5,b A3,b A3,b A2
5. 输出说明
输出自动售货机中商品和存钱盒的信息,包含商品名称、数量,存钱盒面额、数量。根据商品名称的从小到大顺序进行排序,输出结果中商品名称与数量使用一个空格分开,
存钱盒根据钱币面额从小到大排序输出,钱币面额与数量使用一个空格分开,不同信息间使用逗号分开,商品信息与存钱盒信息使用分号分开。
例如,返回结果为:A1 5,A2 9,A3 12;1 5,2 3,5 6
运行时间限制: 无限制
内存限制: 无限制
输入:
投币命令、购买商品命令
输出:
自动售货机中商品和存钱盒的信息
样例输入:
p 5,p 5,p 5,b A3,b A3,b A2
样例输出:
A1 5,A2 9,A3 12;1 5,2 3,5 6
答案提示:

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class VendingMachine {
	public static void main(String[] args) {
		int[] products=new int[]{5,10,14};
		int[] money=new int[]{5,5,3};
		Scanner scanner = new Scanner(System.in);
		while(scanner.hasNext()){
			String line = scanner.nextLine();
			Pattern p = Pattern.compile("(?<=p\\s)\\d");
			Matcher m = p.matcher(line);
			int pay = 0;
			while(m.find()){
				pay += Integer.parseInt(m.group());
				switch (m.group()){
				case "1":
					money[0]++;
					break;
				case "2":
					money[1]++;
					break;
				case "5":
					money[2]++;
					break;
				default:
					break;
				}
			}
			Pattern p2 = Pattern.compile("(?<=b\\s)\\w+");
			Matcher m2 = p2.matcher(line);
			int cost=0;
			while(m2.find()){
				switch (m2.group()){
				case "A1":
					products[0]--;
					cost+=2;
					break;
				case "A2":
					products[1]--;
					cost+=3;
					break;
				case "A3":
					products[2]--;
					cost+=4;
					break;
				default:
					break;
				}
			}
			int back = pay-cost;
			int back5 = back/5>money[2]?money[2]:back/5;
			back = back-5*back5;
			money[2]-=back5;
			int back2 = back/2>money[1]?money[1]:back/2;
			back = back-2*back2;
			money[1]-=back2;
			int back1 = back;
			money[0]-=back1;
			
			System.out.println("A1 " + products[0]+",A2 "+products[1]+",A3 "+ products[2]+",1 "+money[0]+",2 "+money[1]+",5 "+money[2]);
			
		}
		
	}
	
}

分析:这题咋一看像是要用贪婪算法或动态规划来实现,但是人家的题目条件简单,而且限定比较死,所有咱就写了最简单的代码,整个过程就是字符串匹配和加减运算。把钱币额度从大到小排(5, 2, 1),找回的钱和它们挨个作除法、取余,得到的就是最少钱币数目,当然还要考虑每种钱币的原始总数。如果给我们的钱币额度是(5,4,1)这样做就不行了。例如要找回8元,用程序中的方法得到的是(5元*1+1元*3),但最佳方案是(4元*2)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值