数据结构与算法--我们来玩丢手绢(约瑟夫环问题)

我们来玩丢手绢

  • 昨天我们打扑克,今天我们丢手绢
  • 丢手绢我们都知道这个游戏,他的由来由约瑟夫 (Josephus)提出来的
据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,
39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人
该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,
越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,
直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决。
Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
  • 问题来了,我们就不杀呀杀了,还是丢手绢吧,让n个人围成一个环,编号从1 ~n,从1 开始数当数到第m个人时候,他从圈中离开,接着从m+1 个人数,继续m个,在出局,依次复制这个过程,求最后一个出局的人是几号?

方案一,环形链表

  • 题目明显提到了数字的圆圈,自然我们可以构造一个这样类似的数据结构去模拟这种过程。在常用数据结构中,n个阶段的环形链表很好的重现了这种模式
    在这里插入图片描述
  • 我们先构建n个节点的链表,每次删除第m个元素,当环形链表中元素只剩下一个时候得到解
  • 算法分析:
    • 链表头开始,指定位置position,链表尾指定位置before
    • 循环m次,分别将position与before都前移m-1次,得到指定位置
    • 删除psition位置节点,让position指向position.next,统计个数count = n-1
    • 继续以上步骤
  • 以上步骤中循环次数 (n-1)*m次因此时间复杂度应该是O(nm),当m特别大40000 ,时间复杂度会异常的大,非常慢
  • 优化:可以通过取余操作,直接计算出m次循环在 链表中实际的步骤,将 m % count -1得到实际步骤,当m是大数时候,优化效果明显
  • 如上分析有如下代码:
/*** 约瑟夫环问题: 将0,1,2,3,4.....n 这n个数字排列成一个圈圈,从数字0 开始数m个数,删掉他,* 接着从m+1 个开始数在来m个继续删除,一次类推,求出剩下的最后一个数据* @author liaojiamin* @Date:Created in 14:30 2021/7/7*/
public class JosephusForList {public static void main(String[] args) {System.out.println(delNodeForJosephus(40000,997));}/*** 环形链表方法* */public static Integer delNodeForJosephus(Integer n, Integer m){if(n <= 0|| m<=0){return null;}//构造环形队列ListNode head = new ListNode(0);ListNode last = null;ListNode position = head;for (Integer i = 1; i < n; i++) {last = new ListNode(i);position.setNext(last);position = position.getNext();}last.setNext(head);ListNode before = position;position = position.getNext();//当需要移动的位置小于当前数据个数,直接移动指针Integer count = n;while (m <= count){for (Integer i = 0; i < m-1; i++) {before = position;position = position.getNext();}before.setNext(position.getNext());position = position.getNext();count--;}//当m 大于当前需要移动位置个数,取余计算最小移动值while (m > count && count > 1){int move = Math.abs(m%count - 1);for (Integer i = 0; i< move;i++){before = position;position = position.getNext();}before.setNext(position.getNext());position = position.getNext();count--;}position.setNext(null);return position.getValue();}}
  • 以上算法时间复杂度O(nm), 空间复杂度O(n)

约瑟夫环问题

  • 约瑟夫环问题最终还是一个数学问题(数学能救命),我们大概来推导一下

  • 首先定义一个关于n 和 m的方法记为f(n, m),表示每次在n个数字0~n-1中每次删除第m个数字,最后剩下的数字

  • 第一个删除的数字用n,m表示:(m-1)% n , 当且仅当 m>0 n>1的时候,我们记为k =(m-1)% n 如下图
    在这里插入图片描述

  • 接着下一次遍历是从k+1 开始的现有数字总共 n-2个,k+1排第一,也就有如下图所示的顺序

在这里插入图片描述

  • 我们记录第一个删除后的值是 d(n-1, m),与之前的 f(n, m)是同一个规则删除,那么他们最终的结果肯定是一样的,那么就有 d(n-1, m) = f(n, m)

  • 也就是我们将k+1当成是当前的第0 位置,k-1是当前最后的位置,也就是 n-2,那么我们依次推导出各个的位置,k+2是第一个位置

    • n-2之后有n-1,在加上k个数 (n-2)-(k+2)+1=n-k-3
    • n-2 之后有k1个数,(n-2)-(k+1)+1 = n-k+2
    • 同理 0 则是 n-k+1
    • 1 是 n-k
    • k-1则是n-2
    • 用下图对应关系展示
      在这里插入图片描述
  • 如上图,上部分是数据值,下部分是对应的位置,我们可以定义两个集合:

    • A集合是上部分数据值
    • B集合是下部分位置值
    • A,B为非空集, 若存在对应法则f(), 使得对每个 x∈y 都有唯一确 y∈B与之对应, 则称对应法则f()为A到B的映射
  • 如果我们找到了数据值与 位置值的映射关系函数,是不是可以直接通过计算得到下一步中需要删除的数据

  • 此处,我们定义映射为p,推导出p(x) = (x-k-1)%n,映射的逆映射就是p(x) = (x+k+1)%n

  • 根据以上映射规则,映射之前的写中最后剩下的数字 d(n-1, m) = p[f(n-1)+m] = [f(n-1,m) +k +1]%n,将k=(m-1)%n 得到f(n,m) = d(n-1,m)= [f(n-1,m) +k +1]%n

  • 那么我们得到一个递推公式

    • n =1 f(n, m) = 0
    • n>1 f(n, m) = [f(n-1, m)+m ]%n
  • 有了如上公式我们很自然直接递归就能得到第n次的结果

  • 如上分析有如下代码:

/*** 约瑟夫环问题: 将0,1,2,3,4.....n 这n个数字排列成一个圈圈,从数字0 开始数m个数,删掉他,* 接着从m+1 个开始数在来m个继续删除,一次类推,求出剩下的最后一个数据* @author liaojiamin* @Date:Created in 14:30 2021/7/7*/
public class JosephusForList {public static void main(String[] args) {System.out.println(fixJosephusForMath(40000, 997));}/*** 数学方案:通过计算得出发f(n,m)* n=0  f(n,m) = 1* n>1  f(n,m) = [f(n-1,m)+m]%n** */public static Integer fixJosephusForMath(Integer n, Integer m){if(n <= 0|| m<=0){return null;}if(n == 1){return 0;}if(n > 1){return (fixJosephusForMath(n-1, m)+m)%n;}return null;}
}
  • 以上递归实现当n, m值非常大时候几乎不可用,情况通之前文章斐波那契数量原因一样

优化方案三

  • 动态规划解法:在以上推导基础上用一个循环解决
package com.ljm.resource.math.myList;/*** 约瑟夫环问题: 将0,1,2,3,4.....n 这n个数字排列成一个圈圈,从数字0 开始数m个数,删掉他,* 接着从m+1 个开始数在来m个继续删除,一次类推,求出剩下的最后一个数据* @author liaojiamin* @Date:Created in 14:30 2021/7/7*/
public class JosephusForList {public static void main(String[] args) {System.out.println(fixJosephusForMath2(40000,997));}/*** 动态规划实现* 数学方案:通过计算得出发f(n,m)* n=0  f(n,m) = 1* n>1  f(n,m) = [f(n-1,m)+m]%n** */public static Integer fixJosephusForMath2(Integer n, Integer m){if(n <= 0|| m<=0){return null;}int last = 0;for(int i=2;i<=n;i++){last = (last+m)%i;}return last;}}
  • 可以看出,以上实现思路分析非常复杂,但是代码简单时间复杂度O(n),空间复杂度O(1),远优于第一,第二解法

上一篇:数据结构与算法–判断扑克牌是否顺子
下一篇:数据结构与算法–这个需求很简单怎么实现我不管(发散思维)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310314.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

后端开发都应该了解点接口的压力测试(Apache Bench版)

背景 小A&#xff1a;小B&#xff0c;最近调你的接口老是超时呀&#xff0c;8秒都还没返回结果&#xff0c;是不是有性能问题呀&#xff01;小B &#xff1a;我看看~~类似这样的对话&#xff0c;在现实中是时有发生的&#xff0c;不是特别严重的话&#xff0c;往往大家也不会去…

数据结构与算法--这个需求很简单怎么实现我不管(发散思维)

发散思维 程序员是一个高危职业&#xff0c;最近动不动就听到谁谁谁猝死&#xff0c;谁谁谁过劳晕倒&#xff0c;所以面对奇葩问题&#xff0c;我们要淡定&#xff0c; 开发中被产品虐&#xff0c;说的最多的一句话就是这个需求很简单&#xff0c;怎么实现我不管 找工作被面试…

[Java基础]比较器排序Comparator的使用

代码如下: package ComparablePack;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this…

手把手教你如何构建 WPF 官方开源框架源代码

本文转自林德熙的博客&#xff08;blog.lindexi.com&#xff09;导语从去年微软就将 WPF 开源了&#xff0c;差不多现在所有 WPF 的源代码都开源了。在学习框架的时候&#xff0c;我会做一些改动&#xff0c;期望能构建一个自己的版本进行测试。但是作为一个特别大的框架&#…

数据结构与算法--再来聊聊数组

再来聊聊数组 这篇我们来总结一下数组相关的一些算法&#xff0c;数组的特点在于我们能通过下标得到对应数据&#xff0c;时间复杂度在O(1)&#xff0c;之前有多篇文章有数组相关的体系&#xff0c;一下来一个归纳&#xff1a; 数据结构与算法–判断扑克牌是否顺子 数据结构…

[Java基础]泛型基础

可变参数的使用&#xff1a; 代码如下: package CanChangePack;import java.util.Arrays; import java.util.List;public class ArgsDemo01 {public static void main(String[] args){List<String> list Arrays.asList("hello","world","jav…

数据结构与算法--二叉树第k个大的节点

二叉树第k个大的节点 二叉树文章列表&#xff1a; 数据结构与算法–面试必问AVL树原理及实现 数据结构与算法–二叉树的深度问题 数据结构与算法–二叉堆&#xff08;最大堆&#xff0c;最小堆&#xff09;实现及原理 数据结构与算法–二叉查找树转顺序排列双向链表 数据…

Istio 中的 Sidecar 注入及透明流量劫持过程详解

图片来源&#xff1a;上海五角场 by Jimmy Song本文基于 Istio 1.5.1 版本&#xff0c;将为大家介绍以下内容&#xff1a;什么是 sidecar 模式和它的优势在哪里。Istio 中是如何做 sidecar 注入的&#xff1f;Sidecar proxy 是如何做透明流量劫持的&#xff1f;流量是如何路由到…

数据结构与算法--求1~n能组成的所有二叉搜索树的排列

给定一个整数n&#xff0c;生成并返回所有N个节点组成并且节点值从1到n互不相同的不同二叉树&#xff0c;可以按照任意顺序 二叉树文章列表&#xff1a; 数据结构与算法–面试必问AVL树原理及实现 数据结构与算法–二叉树的深度问题 数据结构与算法–二叉堆&#xff08;最大…

Java语法基础50题训练(下)

题目1: HashMap集合存储学生对象并遍历。 需求: 创建一个HashMap集合&#xff0c;键是学生对象(Student)&#xff0c;值是居住地(String)。存储多个键值对象&#xff0c;并遍历。 要求: 保证键的唯一性&#xff1a;如果学生对象的成员变量值相同&#xff0c;我们就认为是同一…

用long类型让我出了次生产事故,写代码还是要小心点

昨天发现线上试跑期的一个程序挂了&#xff0c;平时都跑的好好的&#xff0c;查了下日志是因为昨天运营跑了一家美妆top级淘品牌店&#xff0c;会员量近千万&#xff0c;一下子就把128G的内存给爆了&#xff0c;当时并行跑了二个任务&#xff0c;没辙先速写一段代码限流&#x…

Mongodb查询分析器解析

Mongodb查询分析器 动态相关项目中涉及到数据量大和吞吐量的接口&#xff0c;例如关注页面动态&#xff0c;附近动态&#xff0c;这部分数据都是存储在mongodb中&#xff0c;在线上数据中分类两个mongodb集合存储其中关注动态基于扩散写的设计&#xff0c;数据量已经快到 8 亿…

[Java基础]Collections概述和使用

代码如下: package CollectionDemo01;import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List;public class CollectionDemo01 {public static void main(String[] args){List<Integer> list new ArrayList&l…

链路追踪在ERP系统中的应用实践

源宝导读&#xff1a;随着ERP的部署架构越来越复杂&#xff0c;对运维监控、问题排查等工作增加了难度&#xff0c;本文将介绍通过引入链路追踪技术&#xff0c;提高ERP系统问题排查效率&#xff0c;支撑更全面监控系统运行情况的实践过程。一、导读随着ERP的部署架构越来越复杂…

[Java基础]File基础

File类概述和构造方法: 代码如下: package FileStudyPack;import java.io.File;public class FileDemo01 {public static void main(String[] args){File f1 new File("D:\\JavaDemo\\java.txt");System.out.println(f1);File f2 new File("D:\\JavaDemo&quo…

java 日志乱码_【开发者成长】JAVA 线上故障排查完整套路!

云栖号资讯&#xff1a;【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01;线上故障主要会包括 CPU、磁盘、内存以及网络问题&#xff0c;而大多数故障可能会包含不止一个层面的问题&#xff0c;所以进行…

谈谈登录密码传输这件小事

背景 大大小小的系统其实都离不开登录这个小小的功能&#xff0c;前段时间老黄在审查公司部分系统代码时&#xff0c;发现不少系统的登录还是很粗暴的&#xff0c;粗暴到让人不敢说话的那种。说到登录&#xff0c;结合标题&#xff0c;其实大部分人应该都猜到那个粗暴到让人不敢…

技术分享杂七杂八技术

技术分享 听花谷 距离名宿 6~7 公里左右&#xff0c;丽江网红基地&#xff0c;有举办婚礼的地方听花谷&#xff0c;坐落于玉龙雪山脚下&#xff0c;前有玉龙雪山&#xff0c;后有原始森林。园内共有三处白色空间&#xff0c;第一处共有三层&#xff0c;婚礼举行&#xff0c;发…