欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java 100道经典面试机试笔试题(附可运行代码)

程序员文章站 2022-06-27 20:30:56
导语每篇将有两道经典Java机试题,每道题后面均为大家附上代码,每一道题目力求:能够在JDK11环境下编译在Eclipse JavaIDE中运行通过思路易想易懂易学重点代码有注释第015题 题目名称(难度:★★★☆☆)题目描述:求a/b的小数表现形式。如果a可以整除b则不需要小数点。如果是有限小数,则可以直接输出。如果是无限循环小数,则需要把小数循环的部......

导语

每篇将有两道经典Java机试题,每道题后面均为大家附上代码,每一道题目力求:

  • 能够在JDK11环境下编译
  • 在Eclipse JavaIDE中运行通过
  • 思路易想易懂易学
  • 重点代码有注释

第015题    题目名称(难度:★★☆☆☆)

题目描述:

求a/b的小数表现形式。如果a可以整除b则不需要小数点。如果是有限小数,则可以直接输出。如果是无限循环小数,则需要把小数循环的部分用"()"括起来。

两个整数a和b,其中,0 <= a <= 1000 000,1 <= b <= 10 000

输入示例:

10  1

1    2

1    3

1    7

输出示例:

10

0.5

0.(3)

0.(142857)

思路

首先,先解释一下有些人的疑问:两个整数相除,得到的小数一定只有题目所说的三种情况吗(整除、有限小数、无限循环小数)? 难道不会出现无限不循环小数吗,就像π这个数一样?答案是:不会的。

有限小数,无限循环小数,整数都是“有理数”,而无限不循环小数则是无理数,无理数是无法用分数表示的,即无法用两个整数相除表示。换句话说,能用分数表示的数一定是有理数。

既然两个整数相除必为有理数,那么我们观察平时我们手算除法的过程,找到其中规律,即可解决此题:

假如我们计算1÷6, 那么过程如下:

第一步:上商:0,第一次余数为1

Java 100道经典面试机试笔试题(附可运行代码)





第二步,在余数添加一个0,继续上商1,此次余数为4

Java 100道经典面试机试笔试题(附可运行代码)

第三步,在余数后面添加一个0,继续上商6,此次余数为4

Java 100道经典面试机试笔试题(附可运行代码)

到这里,不难发现,此次余数与上前面某次的余数相同,这意味着循环节即将出现,于是,我们的思路来了,保存每一次的余数,如果此时余数在之前出现过,那么意味着从上一次出现的位置到此处,是一个完整的循环节,那么按照题目要求,将循环节用括号括起来即可。   思路比较简单。

代码

package demo;

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

public class Num1 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt(); // 被除数
		int b = sc.nextInt();
		String list = ""; // 存小数部分的商
		List<Integer> listC = new ArrayList<Integer>();// 存余数
		int c; // a / b的余数
		int d; // a / b的商
		int e; // 保存整数部分的商
		int start = 0; // 循环开始的位置
		int end = 0; // 循环结束的位置

		if ((0 <= a) && (a <= 1000000) && (1 <= b) && (b <= 10000)) {
			c = a % b;
			d = a / b;
			e = d;
			if (c != 0) {
				listC.add(c);
				for (;;) {
					d = c * 10 / b;
					c = (c * 10) % b;
					list = list + String.valueOf(d);
					if (c == 0) {
						start = list.length();//除尽时,需将list全部输出
						end = start;
						// 除尽了,退出
						break;
					} else {
						if (!listC.contains(c)) { // 如果该余数还未出现过,则加到列表中
							listC.add(c);
						} else { // 如果已经包含该数,则说明开始循环
							start = listC.indexOf(c); //记录下循环节开始的位置
							end = list.length();
							break;
						}
					}
					
				}
			}

			System.out.println(
					// 整数部分
					e
					// 是否是小数
					+ (list.length() == 0 ? "" : ".")
					// 非循环节的小数部分
					+ ((list.length() > 0) ? list.substring(0, start) : "")
					// 循环节部分小数
					+ (start == end ? "" : "(" + list.substring(start, end) + ")"));
		}
	}
}

运行结果

Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)

下面再输入一些其他的测试用例,供大家参考程序输出是否正确(这里为了让大家看得更清楚,我做了换行处理)

Java 100道经典面试机试笔试题(附可运行代码)

Java 100道经典面试机试笔试题(附可运行代码)

Java 100道经典面试机试笔试题(附可运行代码)


第016题    题目名称(难度:★★☆☆☆)

题目描述:

一群探险家被困古巴比伦迷宫 ,经过努力,探险家破译出了密码。原来通关需要先打开前方的M个机关的任意一个或多个为打开状态,然后关闭所有机关才能安全通过。探险家还发现了一种带有凸起的圆盘,圆盘可以用来同时反转若干个机关的状态(打开状态反转为关闭状态,关闭状态反转为打开状态,这若干个机关必须同时反转)。为了速记,探险家们用十六进制数字表示一个圆盘。如圆盘能同时控制第3、4、5个开关,圆盘就记为1C(11100)。每次操作一个圆盘,比特位为1的位置的机关同时被反转;而且每个圆盘使用一次后就会碎掉。目前探险家收集到了N个圆盘,问现在探险家可以顺利走出迷宫么?

若探险家手里有0、1、2、3、5五个圆盘,M=7,由于存在1 xor 2 xor 3 = 0, 因此结果是yes;
若探险家手里有0、1、2、2、5五个圆盘,M=7,由于存在2 xor 2 = 0, 因此结果是yes;
若探险家手里有0、1、3、5、9五个圆盘,M=7,由于不存组合使得 xor = 0, 因此结果是no。

包含多组数据,第一行是数据组数。

每组数据中首行为M N,M为机关个数,M <= 360(大部分情况下小于40),N为圆盘个数,
N<=50000;其余为N行圆盘的16进制ID,可以保证每行输入小于2^M
每组一行输出,满足条件输出yes,反之输出no

输入示例:

2
2 3
0
2
2
5 2
4
1C 

输出示例:

yes
no 


思路

老规矩,先解释一下题目,题目看懂了就很简单。

我们就用输入示例的两组数据带入来解释:

第一组数据:

2 3

0

2

2

按照题目意思,前方有2个机关,探险家手里有3个圆盘,这三个圆盘的Id分别为0、2、2, 转换成十六进制分别为00,10,10(因为只有2个机关,所以十六进制位数有2位即可),也就是分别能打开第0个机关(也就是一个都打不开,相当于废物),第二个机关、第二个机关;

Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)

按照题目所述的通关条件:通关需要先打开前方的M个机关的任意一个或多个为打开状态,然后关闭所有机关才能安全通过,那么现有的圆盘能够通过的方式为:①先用圆盘a反转(打开)第二个机关:②再用圆盘b反转(关闭)第二个机关,所有机关均关闭,则通关成功;

第二组数据

5 2

4

1C

按照题目意思,前方有5个机关,探险家手里有2个圆盘,这两个圆盘的Id分别为4、1C, 转换成十六进制分别为00100,11100(因为有5个机关,所以十六进制位数有5位),也就是分别能打开第3个机关,第3个,第4个和第5个机关;

Java 100道经典面试机试笔试题(附可运行代码)

按照题目所述的通关条件:通关需要先打开前方的M个机关的任意一个或多个为打开状态,然后关闭所有机关才能安全通过,那么现在有两种可使用方案:①先使用圆盘a,再使用圆盘b;②先使用圆盘b,再使用圆盘b;(只使用一个显然是不可能通关的)

方案①:先使用圆盘a,将第3个机关反转(打开),再使用圆盘b,同时将第5个、第4个、第3个机关反转(打开、打开、关闭):

Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)

可以看到最后还有第5个和第4个机关是打开状态,没有满足所有机关全部关闭的要求,通关失败

再尝试方案②:先使用圆盘b将,同时将第5个、第4个、第3个机关反转(打开、打开、打开),再使用圆盘a,将第3个机关反转(关闭);

Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)

可以看到最后还有第5个和第4个机关是打开状态,没有满足所有机关全部关闭的要求,通关失败

分析到此,这道题目似乎就明了了许多。如果将机关初始状态记为0,反转一次记为1,那么有如下结果:

机关状态 圆盘id 结果
0 1 1
0 0 0
1 0 1
1 1 0

满足以上运算结果的操作显然是“异或”,那么这道题就可以转化为判断某些圆盘id的十六进制形式按位异或,最后结果每一位都为0,即为成功。如此解题思路瞬间清晰。

代码

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

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt(); // 数据组数
		List<TreasurData> listDatas = new ArrayList<>();
		// 每组数据输入处理
		for (int i = 0; i < num; i++) {
			TreasurData data = new TreasurData();
			data.setM(sc.nextInt()); // 输入M,机关个数
			data.setN(sc.nextInt()); // 输入N,圆盘个数
			String[] Nid = new String[data.getN()];
			for (int j = 0; j < data.getN(); j++) {
				Nid[j] = sc.next(); // 输入N个id号
			}
			data.setNid(Nid);
			listDatas.add(data); // 添加到数据列表里
		}

		for (int i = 0; i < listDatas.size(); i++) {
			// 将十六进制转为十进制
			int[] nidIdDecimal = transferDecimal(listDatas.get(i).getNid());
			// 按位异或得出结果
			boolean result = bitwiseXOR(nidIdDecimal);
			// 将结果保存起来
			listDatas.get(i).setResult(result ? "yes" : "no");
		}

		// 输出结果
		for (int i = 0; i < listDatas.size(); i++) {
			System.out.println(listDatas.get(i).getResult());
		}
	}

	public static int[] transferDecimal(String[] Nid) {
		int[] nidIdBinary = new int[Nid.length];
		for (int i = 0; i < Nid.length; i++) {
			// 十六进制转为十进制
			nidIdBinary[i] = Integer.parseInt(Nid[i], 16);
		}
		return nidIdBinary;
	}

	public static boolean bitwiseXOR(int[] nidIdDecimal) {
		// 每个圆盘的Id按位异或
		int num = nidIdDecimal[0];
		// flag的作用是判断id号是否全0的情况,全0异或结果也为0,但显然是无法通关的;
		int flag = num;
		for (int i = 1; i < nidIdDecimal.length; i++) {
			flag = flag + nidIdDecimal[i];
			num = num ^ nidIdDecimal[i];
		}
		// 如果异或结果为0,且id号不全为0,则说明成功,返回true
		if (flag == 0) {
			return false;
		} else {
			return num == 0;
		}
	}

	static class TreasurData {
		private int M; // M 机关个数
		private int N; // N 圆盘个数
		private String[] Nid; // 圆盘Id
		private String result; // 结果,是否能成功通关

		public int getM() {
			return M;
		}

		public void setM(int m) {
			M = m;
		}

		public int getN() {
			return N;
		}

		public void setN(int n) {
			N = n;
		}

		public String[] getNid() {
			return Nid;
		}

		public void setNid(String[] nid) {
			Nid = nid;
		}

		public String getResult() {
			return result;
		}

		public void setResult(String result) {
			this.result = result;
		}
	}
}

运行结果

Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)Java 100道经典面试机试笔试题(附可运行代码)

最后还有一点想说的,
4 5
1
15
3
7
9

这组数据在某平台上的测试用例为yes,

Java 100道经典面试机试笔试题(附可运行代码)

但是我仔细研究了一下,按照题目,所输入的都是16进制的数,那么转换成16进制,分别为

1:00001

15:10101

3:00011

7:00111

9:01001

这五个数二进制数,应该没有办法组合(首先15肯定不能用,不然第5个机关异或结果一定不为0,同理9也不能用,剩下1、3、7中,7不能用,如果7不能用,那么3也不能用,不然第2位机关无法为0,只剩下1,同理1也不能用),使得最后异或结果为0的吧,所以我觉得结果是no。

这道题,欢迎大家积极贡献测试用例,若发现有不对的地方欢迎大家在评论里指出,我只要看到就会回复,谢谢。


以上是本次两道Java机试题

如有不足,欢迎批评指正

本文地址:https://blog.csdn.net/nanguabing007/article/details/89923296