0
点赞
收藏
分享

微信扫一扫

面试题62:圆圈中最后剩下的数字


题目:

0,1,……,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

分析:

经典的解法,用环形链表模拟圆圈

用环形链表来模拟圆圈,执行删除操作,因为链表的删除操作只需要改动引用,不需要移动元素,所以使用数组来模拟。

创新的解法,拿到Offer不在话下

首先定义一个函数f(n,m),表示n个人报数,每次删去报到m的人,最后剩下的那个人的编号。那么f(n-1,m)表示n-1个人报数,每次删去报到m的人,最后剩下的那个人的编号。

假设n=10,m=3,下面开始分析,第一轮删去下标为2的人,那么下标为3的人就变成了队列的首元素,也就是下标从3变成了0,也就是下标减去了m,那么说,以后每次删去一个人的时候,新一轮的下标都是上一轮下标减去m的结果。直到最后,剩下2个人了,删去一个后,剩下1个。此时这1个人,在只有一个人的队列中,下标自然是0,要想找到最后一个被删除的人的下标,也就是剩下2个人的时候,被删除人的下标,就需要用最后一个人的下标加m,这一点和前面分析的减m是反过来的,所以这里要加m。根据上面的分析,最后一个人的下标是0+3=3,此时队列里只有2个人,不可能等于3,所以需要用3对2取模,也就是3%2=1,实际最后被删除这个人的下标是1。

根据前面的分析,也就得到了f(n,m)=(f(n-1,m)+m)%n这个推导式。我们要求f(n,m),按照递归的思路,用循环来实现,就需要从下往上分析,最后只剩下1个人,也就是f(1,m),它的值为0,因为只有1个人在队列中,下标是0。

  • f(1,3)=0;// 此时队列中,只有一个人,所以下标是0。
  • f(2,3)=(f(2-1,3)+m)%n=(f(1,3)+3)%2=3%2=1。
  • f(3,3)=(f(3-1,3)+m)%n=(f(2,3)+3)%3=4%3=1。
  • ……
  • f(10,3)=(f(10-1,3)+m)%n=(f(9,3)+3)%10=3%10=3。

我们计算出了f(10,3)=3,也就意味着,最后剩下的那个人的下标是3。

解法:

经典的解法,用环形链表模拟圆圈

package com.wsy;

import java.util.Iterator;
import java.util.LinkedList;

public class Main {
public static void main(String[] args) {
int n = 10, m = 3;
LinkedList<Integer> linkedList = new LinkedList<Integer>();
for (int i = 0; i < n; i++) {
linkedList.add(i);
}
int count = 0;
Iterator<Integer> iterator = linkedList.iterator();
while (linkedList.size() != 1) {
int value;
if (iterator.hasNext()) {
value = iterator.next();
} else {
iterator = linkedList.iterator();
value = iterator.next();
}
count++;
if (count % m == 0) {
iterator.remove();
System.out.println("删除的值为:" + value);
}
}
System.out.println("剩下的值是:" + linkedList.getFirst());
}
}

创新的解法,拿到Offer不在话下

package com.wsy;

public class Main {
public static void main(String[] args) {
int n = 10, m = 3;
int result = 0;
for (int i = 2; i <= n; i++) {
result = (result + m) % i;
}
System.out.println("最后剩下的下标是:" + result);
}
}

 

举报

相关推荐

0 条评论