·P7算法面试,在线考试系统自动生成考题算法
威哥
俗话说得好,
基础算法记心口,
逻辑训练好帮手,
面试考察你能力,
不会你就吃苦头,
快速掌握算法的两个步骤, 先搞懂原理,再去理解代码,坐稳了,威哥带你上高速。
威哥要聊一个之前带的学生面试时考察的算法题,这个算法题,直接让这位同学面试成功拿到offer,回来跟我讲了他惊心动魄的面试过程,至今让我印象深刻,因为这个算法被应用在例如,在线教育中的考试系统,匹配条件后的随机派送系统项目中,因此,是一个大有所用的算法,听威哥给你慢慢道来,真的不难,小伙伴们准备好了吗,马上开整。
面试官的问题可能是这样的:
1、在一个区间范围内(例如1-100)生成不重复的随机数
2、一次抽取N个不重复的元素
3、如何高效产生多个不重复的随机数
4、随机的插入1-100之间的数字到a[100],不能重复
5、集群服务器抽奖功能:0-9999之间数字,每个用户随机抽取不能重复的数字
6、Java写一个随机生成四位数的程序 每位数字不重复
7、生成一个 1 到 100 的随机数组,但数组中的数字不能重复,即位置是随机的,但数组元素不能重复
面对面试官的这些问题,小伙伴们脑瓜子里是否已经有了答案了呢?其实,咱们来结合实际的项目需求,在线考试系统中生成考试巻功能有这样一个需求:
首先,根据筛选条件,题型的难易度,题型的范围等,从数据库筛选出符合条件的所有题目,再从这些题目中自动生成多道题目。
好了,这下需求应该是非常明确了,开始分析一下解题思路。
也需咱们的思维逻辑是这样的:
咱们的前置条件是:
把所有符合条件的数据放到一个列表中,定义一个用于存储结果的数组。
例如需要随机生成10道题目,不能重复。
1、随机生成第一个数,放到结果数组的第0个位置。
2、随机生成第二个数,与结果数组中已存在的数比较,如果相同,重新生成,直到不同,放入结果数组中。
3、重复第2步,直到生成10个数结束。
根据以上思路,代码实现是这样的:
//finally-vince
public class RandomNumsDemo {
public static void main(String[] args) {
//模拟目标数据
int[] nums = new int[100];
//模拟填充目标数据
for (int i = 0; i < nums.length; i++) {
nums[i] = i+1;
}
//定义一个用于存储结果数据的数组(10个数)
int[] result = new int[10];
boolean flag;
Random r = new Random();
//需要自动生成的次数
for (int i = 0; i < result.length; i++) {
flag=true;
while(flag){
boolean b = true;
//随机生成数组下标
int index = r.nextInt(nums.length);
//每次生成的下标所指向的数据,需要与结果数组依次比较,以排查重复
for (int y = 0; y < result.length; y++) {
if (nums[index]==result[y]) {
b = false;
break;
}
}
//确认不与结果数组中的数重复,那么放入结果数组中
if(b) {
result[i] = nums[index];
flag = false;
}
}
}
System.out.println(Arrays.toString(result));
}
}
OK,实现完毕。
测试结果:
结果是OK的,这就完了吗,非也,实现结果只是咱们的最低要求,算法的最优解才是高程追求的目标
思考一个问题:
随机生成10个数的最少循环次数应该是多少呢?
很显然,以上的代码解题思路,在与结果数组查重的过程中,会消耗N次比较,如果与结果数组中的数据相同,则需要重新随机生成。
如果随机生成10个数,那答案一定是:10次!
那我们应该怎么来保正每次一定不会随机到相同的值呢?
答案是:
把已生成的值排除在下次随机生成的范围之外。
代码走起!
//finally-vince
public class RandomNumsDemo {
public static void main(String[] args) {
int[] nums = new int[100];
for (int i = 0; i < nums.length; i++) {
nums[i] = i+1;
}
int[] results = new int[10];
genRandomNum2(nums,results);
System.out.println(Arrays.toString(results));
}
//这才是最优解
private static void genRandomNum2(int[] nums,int[] results){
Random r = new Random();
int temp = 0;
for (int i = 0; i < results.length; i++) {
int index = r.nextInt(nums.length - i);
results[i] = nums[index];
temp = nums[index];
nums[index] = nums[nums.length-1-i];
nums[nums.length-1-i] = temp;
}
}
}
优化后的代码实现逻辑是这样的:
随机生成一个指定范围的下标,找到原数列中的元素存入结果数组中,然后把原数列中的该值与数列的最后一个元素-i 次的位置进行调换,这样,每次就把被选中的数都会移动到数列的尾端,然后下一次要随机产生下标的范围就排除数列-i,查找的范围会每次缩小,把已选中的数给排除,那被选中的数就无需考虑是否在结果数组中了,肯定不会有重复的值,那随机生成10个数,就只需要10次就完成。
好了,这才是高程要写出来的算法,逻辑简单,效率高。
威哥的《Java快速入实战》课程中有视频介绍,如果文章还没有学会,威哥给你视瓶伺候。