圆圈中最后剩下的数字

题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。当一个数字删除后,从被删除数字的下一个继续删除第m个数字。求出在这个圆圈中剩下的最后一个数字。

分析:本题就是有名的约瑟夫环问题。既然题目有一个数字圆圈,很自然的想法是我们用一个数据结构来模拟这个圆圈。在常用的数据结构中,我们很容易想到用环形列表。我们可以创建一个总共有m个数字的环形列表,然后每次从这个列表中删除第m个元素。

在参考代码中,我们用STL中std::list来模拟这个环形列表。由于list并不是一个环形的结构,因此每次跌代器扫描到列表末尾的时候,要记得把跌代器移到列表的头部。这样就是按照一个圆圈的顺序来遍历这个列表了。

这种思路需要一个有n个结点的环形列表来模拟这个删除的过程,因此内存开销为O(n)。而且这种方法每删除一个数字需要m步运算,总共有n个数字,因此总的时间复杂度是O(mn)。当m和n都很大的时候,这种方法是很慢的。

接下来我们试着从数学上分析出一些规律。首先定义最初的n个数字(0,1,…,n-1)中最后剩下的数字是关于n和m的方程为f(n,m)。

在这n个数字中,第一个被删除的数字是(m-1)%n,为简单起见记为k。那么删除k之后的剩下n-1的数字为0,1,…,k-1,k+1,…,n-1,并且下一个开始计数的数字是k+1。相当于在剩下的序列中,k+1排到最前面,从而形成序列k+1,…,n-1,0,…k-1。该序列最后剩下的数字也应该是关于n和m的函数。由于这个序列的规律和前面最初的序列不一样(最初的序列是从0开始的连续序列),因此该函数不同于前面函数,记为f’(n-1,m)。最初序列最后剩下的数字f(n,m)一定是剩下序列的最后剩下数字f’(n-1,m),所以f(n,m)=f’(n-1,m)。

接下来我们把剩下的的这n-1个数字的序列k+1,…,n-1,0,…k-1作一个映射,映射的结果是形成一个从0到n-2的序列:

k+1 -> 0
k+2 -> 1

n-1 -> n-k-2
0 -> n-k-1

k-1 -> n-2

把映射定义为p,则p(x)= (x-k-1)%n,即如果映射前的数字是x,则映射后的数字是(x-k-1)%n。对应的逆映射是p-1(x)=(x+k+1)%n。

由于映射之后的序列和最初的序列有同样的形式,都是从0开始的连续序列,因此仍然可以用函数f来表示,记为f(n-1,m)。根据我们的映射规则,映射之前的序列最后剩下的数字f’(n-1,m)= p-1 [f(n-1,m)]=[f(n-1,m)+k+1]%n。把k=(m-1)%n代入得到f(n,m)=f’(n-1,m)=[f(n-1,m)+m]%n。

经过上面复杂的分析,我们终于找到一个递归的公式。要得到n个数字的序列的最后剩下的数字,只需要得到n-1个数字的序列的最后剩下的数字,并可以依此类推。当n=1时,也就是序列中开始只有一个数字0,那么很显然最后剩下的数字就是0。我们把这种关系表示为:

                 0                             n=1
f(n,m)={
                [f(n-1,m)+m]%n        n>1

尽管得到这个公式的分析过程非常复杂,但它用递归或者循环都很容易实现。最重要的是,这是一种时间复杂度为O(n),空间复杂度为O(1)的方法,因此无论在时间上还是空间上都优于前面的思路。

///
// n integers (0, 1, ... n - 1) form a circle. Remove the mth from 
// the circle at every time. Find the last number remaining 
// Input: n - the number of integers in the circle initially
//        m - remove the mth number at every time
// Output: the last number remaining when the input is valid,
//         otherwise -1
///
int LastRemaining_Solution2(int n, unsigned int m)
{// invalid inputif(n <= 0 || m < 0)return -1;// if there are only one integer in the circle initially,// of course the last remaining one is 0int lastinteger = 0;// find the last remaining one in the circle with n integersfor (int i = 2; i <= n; i ++) lastinteger = (lastinteger + m) % i;return lastinteger;
}

 

转自:http://zhedahht.blog.163.com/blog/static/2541117420072250322938/

 

转载于:https://www.cnblogs.com/freewater/archive/2012/07/15/2592717.html

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

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

相关文章

TCP/IP校验和(浅析+实例)

校验和的作用   按照协议的规定&#xff0c;报文到达每一层&#xff0c;首先验证校验和是否正确&#xff0c;丢弃掉不正确的报文&#xff0c;再才会进行后续操作。  那么校验和是怎么计算的呢&#xff1f;  校验和的计算方法(以 IP 首部中的校验和为例) 方法是计算16位的二…

4位数学家获得2018年菲尔兹奖

来源&#xff1a;科学网2018年菲尔兹奖8月1日在巴西里约热内卢市举行的第28届国际数学家大会上揭晓&#xff0c;获奖者为伊朗裔数学家Caucher Birkar、意大利数学家Alessio Figalli、德国数学家Peter Scholze&#xff0c;以及印澳裔数学家Akshay Venkatesh。4位获奖者对数学领域…

ASP.NET GridView控件在列上格式化时间

症状&#xff1a;在GridView绑定日期格式的时候&#xff0c;数据库中的日期为2008-07-04&#xff0c;而GridView显示的是2007-07-04 000000。、 解决办法&#xff1a;想把这后面这多余的零去掉的话在绑定时间的那一列源码后面加上一句话就可以了&#xff0c;如下红色的部分 <…

spark-submit 参数设置

在使用spark时&#xff0c;根据集群资源情况和任务数据量等&#xff0c;合理设置参数&#xff0c;包括但不限于以下&#xff1a; 参数说明masteryarn E-MapReduce 使用 Yarn 的模式yarn-client&#xff1a;等同于 –-master yarn —deploy-mode client&#xff0c; 此时不需要…

科学研究发现,盲人用时间感知空间

来源&#xff1a;中国科学报摘要&#xff1a;在书籍和电影中&#xff0c;盲人通常用超敏感的听力帮助他们在现实世界中穿梭。在书籍和电影中&#xff0c;盲人通常用超敏感的听力帮助他们在现实世界中穿梭。但是&#xff0c;8月1日发表在iScience杂志上的一项研究表明&#xff0…

SharePoint创建web application的时候报错

今天在SharePoint Server上创建一个web application的时候报错了。 The password supplied with the username ***\*** was not correct. Verify that it was entered correctly and try again. 我之前是改过administrator的密码,但确实用stsadm.exe -o updatefarmcredentials…

传输层(学习笔记)

传输层基本概念&#xff1a; 传输层负责端与端之间的数据传&#xff0c;主要有两大知识点&#xff1a;TCP和UDP 五元组 在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看); 端口号范…

随机读写 vs 顺序读写

磁盘是如何存储数据的&#xff1f; 信息存储在硬盘里&#xff0c;把它拆开也看不见里面有任何东西&#xff0c;只有些盘片。假设&#xff0c;你用显微镜把盘片放大&#xff0c;会看见盘片表面凹凸不平&#xff0c;凸起的地方被磁化&#xff0c;凹的地方是没有被磁化&#xff1b…

C# 析构函数(Destructor)和终结器(Finalizer)——托管资源的释放

本文内容 使用析构函数释放资源 Object.Finalize 方法 资源的显式释放 使用析构函数释放资源 析构函数用于析构类的实例。 不能在结构中定义析构函数。只能对类使用析构函数。 一个类只能有一个析构函数。 无法继承或重载析构函数。 无法调用析构函数。它们是被自动调用的。 析…

教育部:建设100+AI特色专业, 500万AI人才缺口要补上!

来源&#xff1a;网络大数据摘要&#xff1a;为落实《国务院关于印发新一代人工智能发展规划的通知》&#xff0c;为我国新一代人工智能发展提供战略支撑&#xff0c;教育部在近日正式发布了《高等学校人工智能创新行动计划》。AI再次被提上国家级日程!为落实《国务院关于印发新…

TCP三次握手详解及面试题

为什么必须是三次握手&#xff1f; 大家都知道传输层&#xff08;点击这里去传输层&#xff09;中的TCP协议是面向连接的&#xff0c;提供可靠的连接服务&#xff0c;其中最出名的就是三次握手和四次挥手&#xff0c;今天先讲解三次握手&#xff08;四次挥手点这里&#xff09;…

git 撤销修改:未push 、已push

场景&#xff1a;不小心把一次错误的代码push到远程服务器上的分支上&#xff0c;需要立即删除/撤销这次代码提交。 具体方法&#xff0c;git命令&#xff1a; git loggit reset --hard <commit_id>git push origin HEAD --force【命令详解】 获取commit_id&#xff1…

跳过堡垒机,一键登陆

使用场景&#xff1a; 在登陆公司堡垒机时&#xff0c;一般需要个人密码动态密码&#xff08;常为OTP密码&#xff09;&#xff0c;本文通过自动生成OTP密码实现一键登录。 如果是静态密码&#xff0c;跳过第一步&#xff0c;第二步去掉动态密码部分 第一步&#xff1a;获取…

一条光纤的传输容量高达 661Tbps(附论文)

来源&#xff1a;云头条摘要&#xff1a;研究人员将全世界目前的光纤容量塞入到一条链路中。社会对数据的渴求永无止境。事实上&#xff0c;想想这个就令人相当惊讶&#xff1a;平均的互联网流量是每秒几百兆兆位&#xff0c;耗电量约占我们发电量的8%。这一切用来传输猫咪即时…

android:给程序加锁

new Thread() {Overridepublic void run() {// 看门狗, 不停的查看当前activity任务栈的栈顶while (true) {// 首先获取到最上面的任务栈, get(0) 获取到任务栈栈顶的activityString packname activityManager.getRunningTasks(1).get(0).topActivity.getPackageName();for (L…

tcp四次挥手,为什么是四次?

上一篇博客说了三次握手为什么是是三次&#xff08;点这里&#xff09;&#xff0c;那么现在就介绍一下四次挥手。大家都知道TCP是全双工的&#xff0c;再建立连接时的三次握手中的SYN和ACK一起发送&#xff0c;这里就会有疑问&#xff0c;为什么在四次挥手的时候没有将SYN和AC…

市值破万亿美金的苹果 近年在AI上搞了些新动作

来源&#xff1a;网易智能2007年&#xff0c;中石油在中国A股市场上市首日市值曾达到1.1万亿美元。11年之后&#xff0c;当地时间8月2日&#xff0c;苹果公司盘中市值也超过1万亿美金&#xff0c;成为继中石油后的第二家破万亿公司。苹果股价以207.39美元收盘&#xff0c;涨幅为…

Install VMware tools 解决(物理主机WIN7X64和VM下的REHAT LINUX AS4共享文件)

这里以Windows 7 X64、VMware Workstation 8、Rehat Linux AS4为例&#xff0c;其它环境类似。 1. 准备工作 打开VMware WorkStation&#xff0c;并启动Rehat Linux AS4 选择vmware workstation程序菜单中VM >install VMware tools... 2. 安装软件包 在/media/VMwareTools/…