您的位置:首页 > 职场人生

面试题45:圆圈中最后剩下的数字

2015-07-08 11:06 295 查看
题目:0,1,...,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前四个数字一次是2、0、4、1,最后剩下的数字为3.

  本题是有名的约瑟夫环问题。

解法一:经典的解法,用环形链表模拟圆圈

如果面试官没有特殊要求,可以用模板库中的list来模拟一个环形链表,而list本身不是一个环形结构,因此每当迭代器扫描到链表末尾的时候,

要记得把迭代器移到链表的头部。

int lastRemaining(unsigned int n, unsigned int m)
{
if (n < 1 || m < 1)
return -1;
list <int>numbers;
for (int i = 0; i < n; ++i)
numbers.push_back(i);
list<int>::iterator current = numbers.begin();
while (numbers.size() > 1)
{
for (int j = 1; j < m; ++j)
{
++current;
if (current == numbers.end())
current = numbers.begin();
}
current = numbers.erase(current);
if (current == numbers.end())
current = numbers.begin();
}
return *current;
}


这种思路的时间复杂度为O(MN),空间复杂度为O(N)。

解法二:创新的解法

  首先定义一个关于n和m的方程f(n,m),表示每次在n个数字0,1,...,n-1中每次删除第m个数字后最后剩下的数字。经过分析(过程参考《剑指Offer》)得到:

n = 1时,f(n,m) = 0;

n > 1时,f(n,m) = [f(n-1,m)+m]%n;

int lastRemaining(unsigned int n, unsigned 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: