1. 问题引入
今天同学给我发了一个题目,让我做。题目是这样的:
2. 问题抽象
这个问题不难,相信高中生都可以做的出来,大致思路就是:
- 首先随机挑出k员工分为k组,这样可以保证每一个组至少有一个员工;
- 然后将剩余的员工随机分到k组中。
那么这么简单的题目为啥还要提一下呢?这是一个公司的笔试题,给60分钟解答时间。但是真的当我动手的时候,才发现这里有一个坑。
第一步中要求每次随机挑出一个员工,如何保证已经被挑出的员工不再参加分组?当然python有一个random.choice()
,可以随机挑出一个,然后将该员工删除即可。但是java没有这样的函数,只有random.nextInt(bound)
,假如有12个员工,使用random.nextInt(12)
,随机返回一个员工的序号后,比如说是6号,那么再次挑员工时,就应该把6号排除了,当然可以接着使用random.nextInt(12)
,并对返回值加一个判断,如果是6号就重新运行一次再重新挑,这样当然可以,但是到了后面只剩三四个人的时候,那得重新运行多少次才能不重复挑到一个人呢。还有一种思路,每次挑走一个人之后,就将他后面的所有人往前挪一个位置,然后缩小范围再挑,例如挑走了6号以后,就将6号后面的员工都往前挪,此时7号变6号,8号变7号,…,然后再在剩下的11个人里面挑,这时只需要运行一次random.nextInt(11)
即可,这样不会出现重复。但是这样每次都需要大量的数据移动操作,时间开销太大了。
然后我想了一会儿,突然就想到了,既然6号空缺了,需要对其进行充填,那么直接将最后一个员工(11号)放过来就可以了,其他的员工不动,这样前11个位置都还是未被分组的,使用random.nextInt(11)
挑一个员工即可,然后再用10号员工进行补充,。。。
第二步就简单多了,我的思路是不再随机挑员工,而是为每一个员工随机挑一个组,只需遍历每一个员工,然后运行random.nextInt(k)
为其挑一个组即可。
3. 实现
// 将数组array随机分为k组。
public Map<Integer, List<String>> partitionEmployee(String[] array, int k){
int len = array.length;
if (len < k) {
System.out.println("分组数k大于员工数,无法分组,请重新给出k值!");
return new HashMap<>();
}
Random random = new Random();
Map<Integer, List<String>> groups = new HashMap<>();
// 首先随机选出k个员工放入k个分组中,使得每组至少有一个员工
for (int i = 0; i < k; i++) {
//随机取出一个员工
int index = random.nextInt(len);
List<String> group = new ArrayList<