约瑟夫问题_100分_A/B复用卷_约瑟夫环问题

约瑟夫问题

题目描述:

输入一个由随机数组成的数列(数列中每个数均是大于 0 的整数,长度已知),和初始计数值 m。
从数列首位置开始计数,计数到 m 后,将数列该位置数值替换计数值 m,
并将数列该位置数值出列,然后从下一位置从新开始计数,直到数列所有数值出列为止。
如果计数到达数列尾段,则返回数列首位置继续计数。
请编程实现上述计数过程,同时输出数值出列的顺序。

比如:输入的随机数列为:3,1,2,4,初始计数值 m=7,从数列首位置开始计数(数值 3 所在位置)
第一轮计数出列数字为 2,计数值更新 m=2,出列后数列为 3,1,4,从数值 4 所在位置从新开始计数
第二轮计数出列数字为 3,计数值更新 m=3,出列后数列为 1,4,从数值 1 所在位置开始计数
第三轮计数出列数字为 1,计数值更新 m=1,出列后数列为 4,从数值 4 所在位置开始计数
最后一轮计数出列数字为 4,计数过程完成。输出数值出列顺序为:2,3,1,4。

输入输出描述:

输入描述:

  输入一个由随机数组成的数列

输出描述:

  输出数值出列的顺序

示例1:

输入:
	3,1,2,4
	4
	7
输出:
	2,3,1,4
	说明:
		第一行是初始数列intput array
		第二行是初始数列的长度len第三行是初始计数值m
		数值出列顺序:2,3,1,4

示例2:

输入:
	3,1,2,4,5,8,7,4
	8
	1
输出:
	3,4,4,8,5,1,2,7

示例3:

输入:
	1,2,3,4,5,6,7,8,9,10
	10
	10
输出:
	10,1,2,4,8,5,6,3,7,9

解题思路1:使用一个单链表来进行模拟

使用单链表将所有节点串联起来,然后数节点、模拟删除即可

代码1:

static class Node {
	int value;
	Node next;
}

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	String[] split = scanner.nextLine().split(",");
	int n = Integer.parseInt(scanner.nextLine());
	int m = Integer.parseInt(scanner.nextLine());
	int m2 = m;
	List<Integer> arr = new ArrayList<>();

	// 先构造出链表
	Node head = null;
	Node pre = null;
	for (int i = 0; i < n; i++) {
		Node cur = new Node();
		int value = Integer.parseInt(split[i]);
		cur.value = value;
		arr.add(value);

		if (i == 0) {
			head = cur;
			pre = cur;
		} else {
			pre.next = cur;
			pre = cur;
		}
	}
	// 尾巴指向头结点,形成环
	pre.next = head;
	List<Integer> res = new ArrayList<>();

	// 模拟:每次取余
	int count = n;
	while (count > 1) {
		int index = m % count - 1;
		Node p = head;
		if (index == -1) {
			// 要删除的是尾巴
			while (p.next.next != head) {
				p = p.next;
			}
		} else if (index == 0) {
			// 要删除的是头
			while (p.next != head) {
				p = p.next;
			}
		} else {
			while (index > 1) {
				p = p.next;
				index--;
			}
		}
		// 删除
		Node next = p.next;
		m = next.value;
		res.add(m);
		p.next = p.next.next;
		next = null;

		head = p.next;
		count--;
	}

	// 输出
	res.add(head.value);
	for (int i = 0; i < res.size(); i++) {
		System.out.print(res.get(i));
		if (i != res.size() - 1) {
			System.out.print(",");
		}
	}
}

解题思路2:使用队列来进行模拟

和使用链表差不多,都是进行模拟删除

代码2:

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	String[] split = scanner.nextLine().split(",");
	int n = Integer.parseInt(scanner.nextLine());
	int m = Integer.parseInt(scanner.nextLine());
	List<Integer> arr = new ArrayList<>();
	// 输入处理
	for (int i = 0; i < n; i++) {
		arr.add(Integer.parseInt(split[i]));
	}
	
	// 使用队列来模拟
	method(arr, m);
}

// 模拟约瑟夫删除
private static void method(List<Integer> arr, int m) {
	List<Integer> res = new ArrayList<>();
	
	while (!arr.isEmpty()) {
		int currentIndex = m % arr.size() - 1;

		if (currentIndex == -1) {
			// 要删除的是尾巴
			m = arr.remove(arr.size() - 1);
		} else if (currentIndex == 0) {
			// 要删除的是头
			m = arr.remove(0);
		} else {
			List<Integer> tmp = new ArrayList<>();
			while (currentIndex-- > 0) {
				tmp.add(arr.remove(0));
			}
			m = arr.remove(0);
			arr.addAll(tmp);
		}
		res.add(m);
	}

	// 输出
	for (int i = 0; i < res.size(); i++) {
		System.out.print(res.get(i));
		if (i != res.size() - 1) {
			System.out.print(",");
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值