0,1,……,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈最后剩下的那个数字。
这是著名的约瑟夫环问题,下面提供两种解法。
经典解法:使用环形链表
自己创建一个环形链表比较麻烦,这里我使用LinkedList来模拟环形链表。但是LinkedList不是环形的,所有每当迭代器(iterator)扫描到链表尾部时要将它移到头部,从而实现环形。
实现代码:
private static int LastNumOfRing(int n,int m){
if(n<0|m<1){
return -1;
}
List<Integer> list = new LinkedList<Integer>();
//由于JAVA中对集合进行遍历时不能修改集合,所有我将要删除的元素暂时放在temp中,待遍历完再删除list中的元素
List<Integer> temp = new ArrayList<Integer>();
for(int i=0;i<n;i++){
list.add(i);
}
int count=1;
Iterator<Integer> iterator = list.iterator();
int size=list.size();
while(size>1){
if(iterator.hasNext()){
}else{
iterator = list.iterator();//回到开头
}
Integer num = iterator.next();
if(temp.contains(num)){
continue;
}
if(count==m){
temp.add(num);
count=1;
size--;
list.toString();
}else{
count++;
}
}
for (Integer integer : temp) {
list.remove(integer);
}
return list.get(0);
}
创新解法:找规律
首先我们定义一个函数f(n,m)表示每次在0~n-1中每次删除第m个数字最后剩下的那个数字。
经过复杂的推导(省略)我们可以得到以下递归式:
使用循环实现代码:
private static int LastNumOfRing(int n,int m){
if(n<0|m<1){
return -1;
}
int last=0;
for(int i=2;i<=n;i++){
last = (last+m)%i;
}
return last;
}
这种方法实现代码真的是太简洁了,Offer稳了!