首页 > 其他 > 详细

使用链表解决Josephus问题

时间:2020-07-15 20:17:40      阅读:34      评论:0      收藏:0      [点我收藏+]

问题描述:

Josephus问题是下面的游戏:N个人编号从1到N,围坐成一个圆圈。从1号开始传递一个热土豆。经过M次传递后拿着热土豆的人被清除离座,围坐的圆圈紧缩,由坐在被清除的人后面的人拿起热土豆继续进行游戏。最后剩下的人取胜。

 

提供两种方案

package com.light.springboot.algorithm;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;

/**
 * Josephus问题是下面的游戏:N个人编号从1到N,围坐成一个圆圈。从1号开始传递一个热土豆。
 * 经过M次传递后拿着热土豆的人被清除离座,围坐的圆圈紧缩,由坐在被清除的人后面的人拿起热土豆继续进行游戏。最后剩下的人取胜。
 * @author qiaozhong
 */
public class Josephus {
	/**
	 * 方案一:通过循环找list下标进行删除的方法解决约瑟夫问题
	 * @param person
	 * @param num
	 * @return
	 */
	public static String josephus(ArrayList<String> person, int num){
		int i=0;
		while(person.size() > 1){
			//循环num次,确定i
			for(int j=0; j < num; j++){
				i++;
			}
			//当i大于当前总人数时,i减去总人数,使i小于总人数
			while(i >= person.size()){
				i = i - person.size();
			}
			person.remove(i);
		}
		return person.get(0);
	}
	
	/**
	 * 方案二:通过list的迭代器iterator解决约瑟夫问题,速度更快 
	 * @param person
	 * @param num
	 * @return
	 */
	public static String iteratorJosephus(ArrayList<String> person, int num){
		Iterator<String> iterator = person.iterator();
		int count = 0;
		while (person.size()>1) {
			//步骤1:如果到链表尾部,就重新获取迭代器,以重头开始
			if(!iterator.hasNext()){
				iterator = person.iterator();
			}
			//步骤2:只要没有到链表结尾,就一直循环查下一个元素
			while(iterator.hasNext() && count++ <= num){
				iterator.next();
			}
			//步骤3:上边的while结束有两种可能,一种是count循环了num次,那么count++应该大于num,此种情况该删除当前元素
			//另一种是查找到了链表尾部,此种情况不删除当前元素,应该回到步骤1重新执行iterator = person.iterator()继续查找
			if (count > num) {
				count = 0;
				iterator.remove();
			}
		}
		return person.get(0);
	}

	//测试两种方案效率
	public static void main(String args[]){
		ArrayList<String> person = new ArrayList();
		for (int i = 0; i < 800000; i++) {
			person.add(String.valueOf("第" + (i+1) + "位客人"));
		}
		
		long start = new Date().getTime();
		System.out.println(josephus(person, 7) + "获胜!");
		System.out.println("方案一消耗时间:" + (new Date().getTime() - start));
		
		long iteratorStart = new Date().getTime();
		System.out.println(iteratorJosephus(person, 7) + "获胜!");
		System.out.println("方案二消耗时间:" + (new Date().getTime() - iteratorStart));
	}
} 

 

测试结果:

第194525位客人获胜!
方案一消耗时间:43501
第194525位客人获胜!
方案二消耗时间:1

 

分析:

方案一:我们的代码设计部分,我们每次调用remove时,都重新遍历了一遍表,调用n次remove,消耗时间为O(N2)

方案二:通过迭代器能够有效地利用List的删除效率高的特性。因为迭代器的时间是O(1),迭代器的remove时间也是O(1),整体的运行时间理论上是O(N)。

 

使用链表解决Josephus问题

原文:https://www.cnblogs.com/gllegolas/p/13307013.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!