题目链接

LeetCode 面试题62. 圆圈中最后剩下的数字[1]

题目描述



















个数字排成一个圆圈,从数字




开始,每次从这个圆圈里删除第




个数字。求出这个圆圈里剩下的最后一个数字。

例如,

















个数字组成一个圆圈,从数字




开始每次删除第




个数字,则删除的前




个数字依次是










,因此最后剩下的数字是




示例1

输入:
n = 5, m = 3
输出:
3

示例2

输入:
n = 10, m = 17
输出:
2

说明:

























题解

循环链表

用一个循环链表按顺序存储











中的数,然后每




个数删除掉链表中的一个结点,最后剩下的数就是答案了。

这种方法时间复杂度是








,显然太高了,所以这里也不会给大家实现代码。

递推法

首先




个人的编号依次是












,然后踢掉了编号为












的人,这时候剩下的人编号为






















下一个踢掉的人就要从






开始数了,所以我们把剩下的人编号从






开始重新排个序,变成




















。这样编号又变成连续的了,而问题规模缩减成了






个人。

剩下的这






个人的编号我们做一下映射,映射成












,这样就能递推下去求解了。映射的公式就是,映射后的编号为




,那么映射之前的编号就是




















也就是说,如果我们求出了






个人最后剩下的人编号




,那么




个人最后剩下的人编号就是


















表示




个人最后剩下的人编号,那么就有:






















这样的话时间复杂度就降到了







对于本题这个方法已经够用了,但是如果




非常大,比如











,但是




不是很大,比如






,那么这时候这种方法就会超时了。具体的题目请自行百度 HDU 3089 。

递推法加速

注意观察上面的递推式




















,如果




很小,而




很大的话,递推到后面要加很多次




才会对




求余。所以我们可以直接一下子加很多次




,然后再求余,这样就能加速了。

加了









之后,递推式变成了:

假设加了









之后才产生了取余,那么就有


















,即
























。所以每次都可以加































,代码实现时用下取整,也就是




























此外还需要注意,如果发现










,也就是后面都不需要取余了,那么就直接一步加到底,退出循环得到答案。

这个方法时间复杂度不是很好分析,但应该也是对数级别的。

数学法

这个方法在我之前的文章中已经讲过了:

具体数学-第8课(取整进阶)

韦阳的博客:具体数学-第8课(取整进阶)[2]

知乎专栏:具体数学-第8课(取整进阶)[3]

知乎高赞回答也整理过了一遍:

世界上有哪些代码量很少,但很牛逼很经典的算法或项目案例?[4]

大致思想也是重新编号,做编号映射,但是和上面递推法不同的是复杂度降到了对数级别。

这里就不详细讲了,大家可以去看上面的文章,这里直接给出伪代码:

D = 1
while D <= (m-1)n:D = k
ans = mn+1-D

其中


















不过这个这里的编号是









,所以最后答案要减去




这种方法将时间复杂度降到了



























,用对数换底公式后得到

可以看出,这种方法适用于




特别大,但是




特别小的情况。否则的话如果




很大,分母会非常小,导致复杂度非常高。

代码

递推法(c++)

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

递推法加速(c++)

class Solution {
public:int lastRemaining(int n, int m) {if (m == 1) return n-1;int last = 0, t = 1;for (int i = 2; i <= n; i+=t) {t = (i-last+m-3) / (m-1);if (i+t-1 > n) {last += (n-i+1)*m;break;}(last += t*m) %= (i+t-1);}return last;}
};

数学法(c++)

class Solution {
public:int lastRemaining(int n, int m) {long D = 1, end = (long)n*(m-1);while (D <= end) {D = (m*D+m-2) / (m-1);}return (long)n*m-D;}
};

参考资料

[1]

LeetCode 面试题62. 圆圈中最后剩下的数字: https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/

[2]

韦阳的博客:具体数学-第8课(取整进阶): https://godweiyang.com/2018/04/16/concrete-math-8/

[3]

知乎专栏:具体数学-第8课(取整进阶): https://zhuanlan.zhihu.com/p/35820332

[4]

世界上有哪些代码量很少,但很牛逼很经典的算法或项目案例?: https://www.zhihu.com/question/358255792/answer/974983270

作者简介:godweiyang知乎同名华东师范大学计算机系硕士在读,方向自然语言处理与深度学习喜欢与人分享技术与知识,期待与你的进一步交流~

我的微信:weiyang792321264。有任何问题都可以在评论区留言,也欢迎加我微信深入沟通~

【每日算法Day 74】经典面试题:约瑟夫环,我敢打赌你一定不会最后一种方法!...相关推荐

  1. 程序员面试系列——约瑟夫环

    约瑟夫斯问题(Josephus Problem) 约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,类似问题又称为"约瑟夫环",也 ...

  2. 算法科普:什么是约瑟夫环

    1 问题描述 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知 n 个人(以编号1,2,3-n分别表示)围坐在一张圆桌周围.从编号为 k 的人开始报数,数到 m 的那个人出圈:他的下一个人又从 1 开 ...

  3. 约瑟夫环数据结构c语言程序,数据结构的C语言(类C语言)--单向循环链表--约瑟夫环...

    代码区 约瑟夫环:用类C语言实现!!!可以成功运行!!!不是仅仅的算法,而是实实在在的类C #include #include typedef int ElemType; typedef struct ...

  4. 约瑟夫环Java实现

    面试中可能经常会遇到约瑟夫环问题,逻辑上很简单,就是看怎么实现了,一般而言,最简单最直观的就是利用链表,然后构建一个循环结构,正好是环,最后计算出结果. 遍历环形链表会是一个无限循环,如果链表中的数据 ...

  5. java 实现约瑟夫环

    这一次是借鉴模仿别人写的代码,以前觉得不好将数据结构的链结构什么的迁移到java上来使用,但这一次确实让我感受到了可以自己构造数据结构,然后使用类似链的方式来解决约瑟夫环,有所顿悟.不多说,继续上代码 ...

  6. # R语言——约瑟夫环

    约瑟夫环: n个人围成一个圈,从第一个人点名,每数到第三个人,这个人移出圈外, 依次类推,求最后留下来的人编号是? 思路:每次循环重新编码序号作为names,并根据names 进行筛选 拓展:约瑟夫环 ...

  7. 循环列表实现约瑟夫环

    1.作业需求 利用循环列表实现约瑟夫环 looplink.h来实现函数声明 #ifndef __LOOPLINK_H__ #define __LOOPLINK_H__ typedef int data ...

  8. 浙江高考VB之约瑟夫环

    浙江信息技术Giao考之 "约瑟夫环" 在浙江信息技术高考中,有一种题型叫做 约瑟夫环题; 首先,约瑟夫环是什么东西? 鲜活的栗子: 我们现在有6个小朋友,分别标号为1 ~ 6.从 ...

  9. n个人围成一个圈报3,或者约瑟夫环,或者丢手绢

    标题:n个人围成一个圈报3,或者约瑟夫环,或者丢手绢 下面这个视频,可以让你了解什么是约瑟夫环,此后,自己写代码实现一下,可以看看我的代码作为参考, 参考视频: 调用,n=10,编号从1-10,sta ...

  10. 约瑟夫环c语言代码 指针,约瑟夫环C语言实现源代码(1)

    前天笔试有个约瑟夫环的问题,怪不得人家没通知我面试,原来我的约瑟夫环做的确实有问题,昨天晚上又重新做了下,下面上源代码: /* file:osephu.cpp author:www.5dkx.com ...

最新文章

  1. 《ArcGIS Runtime SDK for Android开发笔记》——数据制作篇:发布具有同步能力的FeatureService服务...
  2. Android入门学习教程PDF免费下载
  3. php域名转发,php 域名转发程序
  4. AT91RM9200Linux移植笔记(三)-移植Linux kernel 2.6.17
  5. kotlin 扩展类的功能_Kotlin程序| 扩展功能功能
  6. C语言把整数转换为字符串
  7. gecode int branch
  8. PAT 乙级真题题解 java实现
  9. php ms5解密,「phpmd5解密」解析php混淆加密解密的手段
  10. Docker--docker ps 命令与结果解析
  11. quartz 整合 postgresql 附带例子
  12. word 中的背景图片(浮动图形)怎么批量删除
  13. 做项目与做产品的区别详解
  14. Unity3D笔记第十六天——Mecanim动画系统
  15. Linux DMA Engine framework(2)_功能介绍及解接口分析
  16. 内存管理(二) - MRC关键字解读
  17. 思科模拟器出现Translating XXXX...domain server (255.255.255.255) 解决办法
  18. 基于GEE的制作全球任意地方时间序列数据动画的方法
  19. jquery mobile mobiscroll 日期插件使 用mobiscroll
  20. openwrt生成固件(dd命令)

热门文章

  1. colorscheme-如何vim颜色风格
  2. ADO.Net 数据库访问技术
  3. hasCode in Java
  4. 排序趟[置顶] Java和C实现的冒泡排序(基本思想)
  5. 今天主要改了罗宾钢琴的首页图片缩放问题
  6. 【leetcode】二叉树的深度以及树是否平衡的问题
  7. 爬虫练习五:多进程爬取股市通股票数据
  8. 20172330 2018-2019-1 《程序设计与数据结构》实验一报告
  9. gvim下用Vundle安装solarized主题的方法
  10. [LeetCode]Letter Combinations of a Phone Number