原题参见july大神博客系列【微软面试100题】
题目描述:n个数字(0到n-1)排成一个圆圈,从0开始每次删除第m个数字。求剩下的最后一个数字。
分析思路:(本题亦见于《剑指offer》面试题45)
假设第一个删掉是元素k(其中k = (m-1)%n),那么下一轮将从剩下的n-1个元素删掉从元素k+1开始的第m个元素。若将元素k+1看成是第0个元素。
则存在映射:k+1 → 0,k+2 →1,...,n-1→n-k-2,0 →n-k-1,1→n-k,...,k-1→n-2(映射函数为p(x) = (x-k-1)%n)
如果用f(n,m)表示从0开始,每次在n个数字中删掉第m个数字最终留下的数字,那么f(n-1,m)就表示从0开始,每次在n-1个数字中删掉第m个数字最终留下的数字
于是存在关系式:f(n,m) = [f(n-1,m)+k+1]%n = [f(n-1,m) + m]%n. 又当n=1时,f(1,m) = 0.于是通过递归或迭代的方法都能求解出来。
(更深入阐述:假设最后留下的数字是1,即f(n,m)=1,那么删除第一个数后,重新将k+1看成是0,那么最后留下的数字仍是1,只不过通过映射,这个“1”变成了“n-k”,所以得通过逆映射把“n-k”变回“1”,于是有f(n,m) = [f(n-1,m)+k+1]%n = [f(n-1,m) + m]%n)
代码如下:
int Joseph(int n, int m)
{
if( n < 1 || m < 1 )
return -1
int last = 0;
for (int i = 2; i <= n; i++)
last = (last + m)% i;
return last;
}