出圈问题---n个人围成一圈,数到key或者key的倍数,出圈,问剩下的最后一个人原来的位置是多少?
java版
1、n个人围成一圈,说明它是重复循环的,头就是尾。
2、每次数key或者key的倍数,例如3,就是数到3或者3的倍数这个数出圈,然后继续数。
3、当我们数完一圈,接着头部继续数,最好的方法就是取余,就可以忽略掉圈数的问题。
4、保存数据的方式,可以采用数组,可以采用链表。我们这里采用链表,因为数组删除元素不会自动回退和移动的,尽管数组效率要高一些。
5、由于每次删除元素之后,元素的个数会减少一个,元素会向前移动,所以下一个3(key)的倍数只需要走两步就可以,所以我们把下标每次删除元素之后-1.这样可以保证每次删除的元素都是3(key)的倍数。
6、如果使用从0开始的下标计算,那么初始化的时候index应该为-1,这样就相当于模拟了元素已经删除了一个。
package com.company;
import java.util.LinkedList;
import java.util.List;
/**
* 经典算法-出圈 n个人 围成一圈 数到3或者3的倍数就出去,问最后剩下来的人的位置。
*/
public class OutCircle {
public static Integer out(int total, int key) {
List<Integer> list = new LinkedList<>();
for (int i = 1; i <=total ; i++) list.add(i);//循环赋值初始位置。从1开始。
int index = -1; //下标从0开始 , 初始化为-1;
while (list.size() > 1) {
index = (index + key) % list.size(); //对总数取余。 index+key,表示每次数key(3)个数
list.remove(index--);//把当前元素删除,然后下标-1.
}
return list.get(0);//返回最后一个元素的最开始的位置。
}
public static void main(String[] args) {
System.out.println("最后剩下的人的位置:"+out(50,3));//打印出来
}
}
输出结果:
最后剩下的人的位置:11
Process finished with exit code 0