书上说这是著名的约瑟夫环问题。这个要频繁删除操作,所以用list做就很容易想到了。list是单向的,所以当迭代器走到尾部的时候,再让它回到头部就可以形成环。
1 class Solution { 2 public: 3 int LastRemaining_Solution(int n, int m)//n个人,从第一个开始数,第m个退出,循环往复 4 { 5 if (n == 0) 6 return -1; 7 list<int> li; 8 //定义一个迭代器,用迭代器找到m 9 //重新定义迭代器指向上一个迭代器的下一个 10 //删除第一个迭代器的m位 11 for (int i = 0; i < n; i++) 12 li.push_back(i); 13 14 auto f = li.begin(); 15 //li.erase(*(f + m)); 16 while (li.size() > 1) 17 { 18 for (int i = 0;i<m-1; i++)//寻找第m个数 19 { 20 f++; 21 if (f == li.end())//循环起来 22 f = li.begin(); 23 } 24 auto next =++ f;//定义一个新的迭代器,保存第一个迭代器的下一个的值。 25 //因为下一步有list的删除操作会令第一个定义的迭代器失效 26 if (next == li.end()) 27 next = li.begin(); 28 f--; 29 li.erase(f); 30 f = next; 31 } 32 33 return *f; 34 } 35 };
看到剑指offer上的第二种解法。将这个题目推到出一个递归的公式。这样关键是要想到递归,其次想到递归要会推导公式,数学好难,o(╥﹏╥)o不过这个代码确实很简洁,想清楚思路用这种方法做很有用。
1 class Solution { 2 public: 3 int LastRemaining_Solution(int n, int m) 4 { 5 if (n <1||m<1) 6 return -1; 7 int last = 0; 8 for (int i = 2; i <= n; i++) 9 last = (last + m) % i;//计算每一轮的值 10 return last; 11 } 12 };