【约瑟夫环】圆圈中最后剩下的数字

news/2024/10/23 5:40:11/

题目描述

0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

解题思路

思路一,直接使用对列模拟

    public int lastRemaining(int n, int m) {Queue<Integer> queue = new LinkedList<>(), tmpQ = new LinkedList<>();for (int i = 0; i < n; i++) {queue.add(i);}while (queue.size() > 1) { //循环1int len = queue.size();int k = 0;while (k < (m - 1) % len) { //循环2tmpQ.add(queue.poll());k++;}queue.remove();//移出第m个while (!tmpQ.isEmpty()) {queue.add(tmpQ.poll());}}return queue.peek();}

以lastRemaining(5,3)为例,初始化对列,queue =[0,1,2,3,4]。
第一次移出(数2个到tmpQ中):tmpQ:[0,1] 。移出第3个:queue.poll(),此时queue为:[3,4]
移除后产生的新数组,将tmpQ加入到queue尾部即可:[3,4,0,1]
同理可得,第二次移出数字0,移出后的queue:[1,3,4]
第三次移出数字4,移出后的queue:[1,3]
第4次移出数字1,移出后的queue:[3]
此时对列queue只剩数字3,返回即可

复杂度分析

外层while循环1需要遍历n-1次,内层while循环2需要遍历m次,总的时间复杂度为O(m*n),当m、n比较大时,程序执行会很慢。

思路二,动态规划

输入n=5,m=3,记该问题为【5,3】问题,设解(即最后留下的数字)为:F(5)

  • 【5,3】问题:数字环为:0 1 2 3 4 ,解为F(5)
  • 【4,3】问题:数字环为:0 1 2 3 , 解为F(4)

对于【5,3】问题,首轮删除环中第3个数字后,得到一个长度为4的环:3 4 0 1。可以看到也变成了一个【4,3】问题,只是环不再是0 1 2 3。将【4,3】问题和【5,3】删除一轮后的环对照来看,即:
环a. 3 4 0 1 ==>【5,3】删除首轮后的环
环b. 0 1 2 3 ==>【4,3】的环,即F(4)
假设 F(4)=1,那么【5,3】删除后的解一定等于4(即a,b两者都是从4个数字里面删除第3个数字,最后留下的数字的索引一定是相等的),所以只需找到a,b环中数字的对应关系即可有F(n-1)推出F(n)
观察可得到下列对应关系:
F ( n ) = ( F ( n − 1 ) + m ) % n F(n)=(F(n-1)+m)\%n F(n)=(F(n1)+m)%n
F ( 1 ) = 0 F(1)=0 F(1)=0,所以可以直接用递归完成

    public int lastRemaining2(int n, int m) {if (n == 1) return 0;return (lastRemaining2(n - 1, m) + m) % n;}

如果不用递归,通过动态规划也可,两者思路是一样的(已知F(1),通过递推关系得到F(n))

    public int lastRemaining(int n, int m) {int a = 0;for (int i = 2; i <= n; i++) {a = (a + m) % i;}return a;}

http://www.ppmy.cn/news/1090098.html

相关文章

Promise常用方法笔记

mixin.methods.getList(xxx) 是axios的二次封装 是通过Promise进行基本封装 let a mixin.methods.getList(toosSet.gettype);let b mixin.methods.getList(toosSet.gettypes);let c mixin.methods.getList(toosSet.gettypess);Promise.all([a, b, c]).then((res) > {aler…

结构体做函数参数

①值传递 ②地址传递 #include <iostream> #include <algorithm> #include <string> using namespace std; struct stu {int age;string name; }; void printStu(stu a) {cout << a.age << << a.name << endl; } void printstu(…

node基础概念

前言&#xff1a;可以让别人访问我们的网页&#xff0c;可以开发服务端应用、工具类应用、桌面端应用&#xff08;electron&#xff09; 1. 计算机基础 概念&#xff1a;CPU 内存 硬盘 主板 显卡 2. 进程和线程 概念&#xff1a;进程是一个程序的执行&#xff0c;线程组合形…

vue3请求成功后实现类似打字效果输出

要在 Vue 3 中实现请求成功后的类似打字效果输出&#xff0c;您可以使用 ​axios​ 或其他适合您的方法来发起异步请求。在请求成功后&#xff0c;您可以将返回的文本存储在响应式对象中&#xff0c;并使用一段时间间隔逐个字符地将文本输出到界面上。下面是一个示例代码&#…

【阅读笔记】如何正确地学习编程?

2023年9月1日&#xff0c;周五上午 本次阅读的文章来自&#xff1a; 为什么我学个 JAVA 就已经耗尽所有&#xff0c;而有些人还能同时学习多门语言&#xff1f; - invalid s的回答 - 知乎 https://www.zhihu.com/question/485917018/answer/2216877333 令我感到有趣的是&#…

附录1-爬虫的一些技巧

目录 1 寻找url与显示内容的关系 2 修改请求头 3 局部刷新 4 阅读返回信息 5 多尝试页面其他的使用方式 6 尝试不同类型参数 7 表单类型的post多用data发&#xff0c;接口类型的post多用json发 8 消除degger 9 你在浏览器上看到的html与你下载下来的html不一…

3.msfconle

目录 1 进入msfconsole 2 连接postgresql数据库 3 msfconsole基本用法 4 更新msf 5 搜索脚本 search 6 查看脚本信息 info 7 设置参数 8 重新设置参数与取消参数 9 退出当前模块 back 10 查看域名基本信息 dig 11 查看域名的详细信息 whois 1 进入msfco…

数据库-索引

介绍&#xff1a; 索引是帮助数据库高效获取数据的数据结构 优缺点&#xff1a; 优点&#xff1a;提高数据查询的效率&#xff0c;降低数据库的IO成本 通过索引列对数据进行排序&#xff0c;降低数据排序的成本&#xff0c;降低cpu消耗 缺点&#xff1a;索引会占用存储空间 索…