16. 微软面试题:n个数字(0,1,n-1)形成一个圆圈,从数目字0开始

16. 微软面试题:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始
题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,
每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字。

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


分析:

最初的想法是想设计一个数据结构,实现随机存取,又能快速删除的数据结构。最开始想到的是循环数组,发现删除不好处理,得移动大量的数据,效率上比较低。

如果使用链表的话,又没法实现随机存取。


后面使用百度搜了下,看到一种方法,看看他的分析:

n个数字(0,1,…,n-1),先删除第m个数字,再从后 开始。。。

假设k = (m-1)%n,n个数字的位置为:f(n), 删除第k个数字后的位置为:f(n-1),删除剩一个数字位置为:f(1)

f(n)                f(n-1)

k+1     ->     0 
k+2     ->     1 
… 
n-1      ->     n-k-2 
0         ->     n-k-1 
… 

k-1     ->    n-2

由此可以推出:f(n) = (f(n-1) + k + 1)%n  并且f(1) = 0 ,其中 k = (m-1)%n

所以 f(n) = (f(n-1) +m)%n。


那么实现如下:

#include<iostream>


using namespace std;

int findpos(int n, int m)
{
        if(n < 1 || m < 1)
                return -1;
        
        if(n == 1)
                return 0;
        return (findpos(n-1, m) + m)%n;
}

int main()
{
        int n = 10;
        int m = 5;
        cout << " 0,1,...,10 从0开始数5开始删除,最后为: " << findpos(10, 5) << endl;
        return 0;
}


 输出结果为:

0,1,...,10 从0开始数5开始删除,最后为: 2