数三退一问题(约瑟夫环问题)

写在开头:
这段文字编辑于2020年6月18日,20:39分,加班…
这篇博客是我2017年初,初学Java的时候写的,题目是“数三退一问题”,题目的来源是马士兵老师2005、2006年在尚学堂的时候录的那版最经典的Java视频,好像是在第三章讲的。但是那会儿我还不知道,这个就是一个初版的约瑟夫环问题。
今年春天跳槽找工作,面试百度,一面是远程面试,在一个叫做“ShowMeBug”的面试平台上写代码,然后面试官让写一个约瑟夫环问题,后来才知道,就是数N退一问题。
所以说,不要小看任何一段代码,无论多短多简单,你永远也不知道可能未来的某一天就会用得到。
现在已经毕业一年了,真心感觉到生活不易,不知道自己在Java这一行能如何,也不知道自己35,40岁之后还能不能在这一行保持核心竞争力,还能不能有实力和精力继续在程序员这一行业里坚持下去。
写在这篇文章前面我也不知道要说些什么,可能只是来自一个工作一年的程序员的感慨吧。


原文
问题描述:
假设有500个孩子,手拉手围成一个圈,从第一个孩子开始报数,第一个孩子报1,第二个孩子报2,第三个孩子报3,那个第三个孩子退出这个圈,然后第四个孩子继续报1,第五个孩子报2…每个数到3的孩子都退出这个圈,直到圈内只剩1个孩子,问这个孩子是第几个孩子?

这个问题有两种解法,第一种方法是采用数组的方式:首先建立一个布尔类型的数组,数组内的值为true的位置表示该位置的孩子在圈内,数组内的值为false的位置表示该位置的孩子由于数到了3退出了这个圈,然后采用while循环,并设置一个计数器,当计数器数到3时该位置的值变为false,直到圈内只有一个孩子,再遍历一次数组并输出这个位置。
解释起来语言可能比较难以理解,我们直接看代码:

public class CountThreeQuit {
	public static void main(String[] args) {
		boolean[] a = new boolean[500];
		for(int i=0; i<a.length; i++) {
			a[i] = true;
		}//将数组初始化为true
		
		int leftCount = a.length;  
		int index = 0;   //下标计数器
		int count = 0;   //计数器

		while(leftCount > 1) {
			if(a[index] == true) {
				count++;
				if(count == 3) {
					leftCount--;
					a[index] = false;
					count = 0;
				}
			}
			index++;

			if(index == a.length)
				index = 0;
		}

		for(int i=0; i<a.length; i++) {
			if(a[i] == true)
				System.out.println(i);
				//再次遍历,寻找值为true的位置
		}
	}
}

这段代码最后输出的值为435,代表着最后剩下的孩子下标为435,即第436个孩子。

第二种思想是面向对象的思想,首先我们看这个题目中一共有两个类:孩子、孩子围成的圈,那我们就定义出Kid和KidCircle两个类,并在KidCircle中定义出add和delete的方法,我们同样看代码:

public class Count3Quit {
	public static void main(String[] args) {
		KidCircle kc = new KidCircle(500);
		int countNum = 0;
		Kid k = kc.first;
		/*
		for(int i=0; i<500; i++) {
			k.id = i;
			k = k.right;
		}
		*/
		while(kc.count > 1) {
			countNum++;
			if(countNum == 3) {
				countNum = 0;
				kc.delete(k);
			}
			k = k.right;
		}
		
		System.out.println(kc.first.id);
	}
}

class Kid {			//定义Kid类
	int id;
	Kid left;
	Kid right;
}

class KidCircle {		//定义KidCircle类
	int count;
	Kid first;
	Kid last;
	
	public KidCircle(int n) {
		//count = n;
		for(int i=0; i<n; i++) {
			add();
		}
	}
	
	public void add() {//增添分多钟情况增添
		Kid k = new Kid();
		k.id = count;
		
		if(count <= 0) {
			first = k;
			last = k;
			k.left = k;
			k.right = k;
		} else {
			last.right = k;
			first.left = k;
			k.right = first;
			k.left = last;
			
			last = k;
		}
		
		count++;
	}
	
	public void delete(Kid k) {
		if(count == 0) {
			System.out.println("You have no kids in the KidCircle,So you should not delete any more!");
		}
		else if(count <= 1) {
			first = last = null;
		} else{
			k.left.right = k.right;
			k.right.left = k.left;		
		}
		
		if(k == first) first = k.right;
		else if(k == last) last = k.left;
		
		count--;
	}
}

这样程序运行之后同样输出435。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值