描述: 现在有n个竞争者围坐一圈,争夺一个很有吸引力的工作(年薪100w $)。假设这些人编号1,2,。。。,n。第一次从1开始报数,数到m(m>0)的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列。以此类推,直到所有人出列为止。老板说最后一个出列的人将获得这份工作。
如果你也想竞争这份工作,那么你会坐着哪个位置上?
实现一个函数,当老板告诉你n和m时,返回得到工作的那个人的编号。
运行时间限制: 无限制
内存限制: 无限制
输入: 竞争者人数,报数
输出: 最后出列的竞争者的编号。异常则返回 -1。
样例输入: 10,10
如果你也想竞争这份工作,那么你会坐着哪个位置上?
实现一个函数,当老板告诉你n和m时,返回得到工作的那个人的编号。
运行时间限制: 无限制
内存限制: 无限制
输入: 竞争者人数,报数
输出: 最后出列的竞争者的编号。异常则返回 -1。
样例输入: 10,10
样例输出: 8
思路:个人认为该题主要考察答题者的逻辑思维、现实问题抽象成编程模型以及基础编码能力,当你把逻辑理顺了后,其实只需要很短的一段代码就实现了。回到题目上,此题涉及到竞争者报数,当报到m的时候,删除该竞争者,依次循环。抽象出来,可以理解为齿轮问题,一个周长为n(齿尖编号分别为1-n)的齿轮带动一个周长为m(齿尖编号为1-m)的齿轮旋转,每当遇到编号为m的齿尖的时候,周长为n的齿轮去掉对应的齿尖,齿轮变小,以此类推,直到只剩下最后一个齿尖(从微观上来看,此时齿轮为一个圆点),得到该齿尖的编号。于是我们设置两个指针,分别指向两个齿轮接触点对应的竞争者编号和报数的数值,报数每循环一轮(1-m)竞争者少一个,直到竞争者剩下最后一个,得到编号。
图形表示:
具体实现代码(带注释):
import java.util.LinkedList;
import java.util.Scanner;
/**
* Package: com.properties.test
*
* File: GetCompetitorNum.java
*
* Copyright @ 2015 Corpration Name
*
*/
public class GetCompetitorNum {
public static int getNum(int n,int m){
int count = 0;//用于记录报数的数字,在1到m之间循环
int temp = 0; //用于记录报数时所指向的竞争者,当count为m的时候,删除此时temp所指向的竞争者
LinkedList<Integer> list = new LinkedList<>();//用整数模拟每个竞争者,编号为1->n
for (int i = 1; i < n + 1; i++) {
list.add(i); //将n个竞争者放入到list中
}
while(list.size() > 1){ //循环结束条件为:当list中还剩下一个值得时候,即竞争者还剩一个
if(temp == list.size()){
temp = 0; //当temp的值等于list的当前所剩竞争者数量的时候,重置为0
}
count++;
temp++;
if(count == m){
list.remove(temp-1); //报数到m,删除此时temp所指向的竞争者
count = 0; //删除后,报数重置为0,下一轮报数从1开始
temp = temp - 1; //删除后,list少一个竞争者,此时temp所指向的是删除前的下一个竞争者,所以回退一个值
//如果不回退,则下一轮就跳过被删除竞争者的后面一个竞争者,就等于报数跳过了这个人
}
}
return list.get(0); //最后返回剩下的最后一个竞争者
}
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
try {
String str = scanner.nextLine();
int n = Integer.valueOf(str.split(",")[0]);
int m = Integer.valueOf(str.split(",")[1]);
int output = getNum(n, m);
System.out.println(output);
} catch (Exception e) {
System.out.println(-1);
}
scanner.close();
}
}