题目要求:
0,1,...,n-1这n个数排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删词第3个数字,则删除的前四个数字一次是2、0、4、1,因此最后剩下的数字是3.
参考资料:剑指offer第45题
题目分析:
方法1:用环形链表模拟圆圈,链表可以用c++的STL库中的list来表示,删除链表其中一个结点之后,链表还是连续的。
方法2:定义f(n,m),表示每次在n个数字0,1,...,n-1中每次删除第m个数字最后剩下的数字。
先给出关系公式:
可以这样理解:从序列f(n):0~n-1中删除第m个数后,剩下为序列m,m+1,..,n-1,0,1,...,m-2,即序列f(n-1)+m.因此f(n,m) = [f(n-1,m)+m]%n,是采用的映射关系来递推的。
代码实现:
#include <iostream> #include <list> using namespace std; int LastRemaining(unsigned int n,unsigned int m); int LastRemaining2(unsigned int n,unsigned int m); int main(void) { //cout << LastRemaining(5,3) << endl; cout << LastRemaining2(5,3) << endl; return 0; } //方法1 int LastRemaining(unsigned int n,unsigned int m) { if(n<1 || m<1) return -1; unsigned int i = 0; list<int> nums; for(i= 0;i<n;i++) nums.push_back(i); list<int>::iterator cur = nums.begin(); while(nums.size()>1) { for(int i = 1;i<m;i++) { cur++; if(cur==nums.end()) cur = nums.begin(); } list<int>::iterator next = ++cur; if(next == nums.end()) next = nums.begin(); --cur; nums.erase(cur); cur = next; } return *cur; } //方法2 int LastRemaining2(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; }