微软算法100道题

原创 2015年11月20日 16:10:42

题目:

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%n-1,为简单起见记为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%n-1代入得到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 


然后就按这个公式写。。。。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

python 调用opencv读取视频

import cv2 capture = cv2.VideoCapture("video.avi") while True: ret, img = capture.read() re...

c语言实现memcpy

今天到I 公司去面试,面试方式比较特殊,没有笔试,就是2 个面试官,一人一句轮番发问,涉及面很广,涉及到操作系统(MMU 、page out 、process/thread 、semapho...

微软100道算法题之001

下面开始第一题: 输入一颗二元查找树,将该二叉查找树转换成一个排序的双向链表。要求不能创建任何新的节点,只调整指针的方向: 1:二叉查找树的定义我在这里不多解释,无...
  • so_zt
  • so_zt
  • 2012年10月12日 15:27
  • 337

微软面试100道之11 求二叉树中节点的最大距离

求二叉树中节点的最大距离... 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的, 我们姑且定义"距离"为两节点之间边的个数。 写一个程序, 求一棵二叉树中相距最远的两个节点之间的距...

Python的100道经典算法题

按照c语言的100道经典算法题,自己原创写的,就得是自己的练习题了 【程序1】 题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位、十位、个位...

100道经典算法题(76-100)

76.复杂链表的复制 题目:有一个复杂链表,其结点除了有一个m_pNext指针指向下一个结点外, 还有一个m_pSibling指向链表中的任一结点或者NULL。其结点的C++定义如下:  str...

100道经典算法题(26-50)

26.左旋转字符串 题目: 定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。 如把字符串abcdef 左旋转2 位得到字符串cdefab。请实现字符串左旋转的函数。 要求时...

Python的100道经典算法题(1)

按照c语言的100道经典算法题,自己原创写的,水平可能很低,就得是自己的练习题了...

c语言100道经典逻辑算法题

  • 2010年06月04日 13:17
  • 58KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:微软算法100道题
举报原因:
原因补充:

(最多只允许输入30个字)