JAVA学习之路——Josephus problem
Josephus problem简介
Josephus problem
又叫约瑟夫环问题,具体情况是是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
举例
有100个人围成一个圈(编号0-99),从第0号的人开始从1报数,凡报到3的倍数的人离开圈子,然后再数下去,直到最后只剩一个人为止,问此人原来的位置是多少号?
思路说明
首先根据问题,可以将这100人放入某一容器中,此容器可以是数组页可以是集合。然后开始进行数数,每次数到3的倍数时就将其中一个人移出容器,移出99个人之后,剩下的那个人就是我们想要知道号码的那个人。此问题,个人有如下两种实现方法。
链表实现
将数据放入链表中,并且转换为int型方便进行操作,声明了一个变量count作为计数工具。因为本例子中是每次数到3就将数据移出,最后只剩下一个元素时结束循环。
import java.util.LinkedList;
//约瑟夫环
public class Joseph {
public static void main(String[] args) {
LinkedList<Integer> x = new LinkedList<Integer>();
for (int i = 0; i < 100; i++) {
x.add(i+1) ;
}
int count = 1 ;
for (int i = 0; i < x.size(); i++) {
int j = x.get(i) ;//取出x集合中的数据
if( count % 3 == 0 ){
x.remove(i);
i--;
}else{
int backvalue = x.pollFirst();//移除第一元素后,并且得到此元素
x.offerLast(backvalue);//将之前移除的元素添加到此集合的末尾处
i--;
}
count++;
if(x.size()==1){
break ;
}
}
for (int i = 0; i < x.size(); i++) {
System.out.println(x.get(i));
}
}
}
运行结果
91
数组实现
思路大体和链表实现的思路类似,但是数组无法将元素移出数组,所以在循环的时候将数到3倍数的数据置为0视为移出数组。而在下次循环的时候跳过数值为0的元素并且计数器不增加,在最后整个数组剩余数值不为0的元素只剩一个时结束循环
public class Joseph {
public void outArray(int []data,int num)
{
int i =0;
int count = 0;//计数器
int left = 100;//统计剩余数据的变量
while(left!=1) {
count++;
i++;
//此代码的作用是每次数到数值为0的元素时,计数器不变
if(data[i-1]==0) {
count--;
}
//计数器到3时元素出局,同时为了增加显示效果,输出了结果,也可以用if(count%3 == 0)作为判断条件,这样的话count不用清零
if(3==count) {
System.out.print("本次出局的是:"+data[i-1]);
System.out.println();
data[i-1]=0;
count=0;
left--;
}
//因为数组是线性的,所以当i到边界时得重新开始数
if(100==i) {
i=0;
}
}
//执行完毕后,整个数组只剩一个不为0的元素,进行遍历将其输出
for(i = 0;i<100;i++) {
if(data[i]>0) {
System.out.print("最后留下的是:"+data[i]);
}
}
}
public static void main(String[] args) {
int [] data=new int [100];
for (int j = 0; j < data.length; j++) {
data[j]=j+1;
}
Joseph a = new Joseph();
a.outArray(data, 100);
}
}
总结
约瑟夫环问题并不算难,主要是需要明确该从何处着手实现每逢几的倍数就移出,想清楚关键点后,剩下的部分很容易就能写出来了。