题目:0,1,…,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里最后剩下的数字。
思路(1):用环形链表模拟圆圈。
int LastRemaining(unsigned int n, unsigned int m)
{
if(n < 1 || m < 1)
return -1;
unsigned int i = 0;
list<int> numbers;
for(i = 0; i < n; ++i)
numbers.push_back(i);
list<int>::iterator it = numbers.begin();
while(numbers.size() > 1)
{
for(int i = 1; i < m; ++i)
{
++it;
if(it == numbers.end())
it = numbers.begin();
}
list<int>::iterator tmp = ++it;
if(tmp == numbers.end())
tmp = numbers.begin();
numbers.erase(--it);
it = tmp;
}
return *it;
}(2)分析每次被删除的数字的规律直接计算出圆圈中最后剩下的数字。设有n个数字,要删除第m个数字,用f(n,m)表示最后一个数字,设它在序列中的坐标为s。删除第m个数字以后,序列中元素的坐标都发生了转换,原先第m个数字后面的一位下标变为0,后两位下标变为1…,坐标的转换关系为(s-m)%n。那么在删除之前,它在序列中的位置应该为(s+m)%n。删除一个元素之后求最后一个元素的过程同样也可以用函数f表示,f(n-1,m)还原到有n个元素时的坐标就是(f(n-1,m)+m)%n,所以有f(n,
m) = (f(n-1,m)+m)%n,这样就得到删除前后两次的递推公式,我们不必真的去删除第m个元素。但n=1时,只有一个元素0,显然它也是最后一个元素。求解f(n, m)可以用递归的方法,也可以用循环的方法,我们可以用求解斐波那契数列类似的方法从n = 1是逐步增加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;
}
2139

被折叠的 条评论
为什么被折叠?



