剑指offer62. 圆圈中最后剩下的数字(Josephuse约瑟夫环问题) P300
题目:0, 1, …, n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
方法1. 循环链表 (C++官网说list不是循环链表 , 但是为啥所有博客都说是循环呢? )
int LastRemaining_Solution(int n, int k) {
if (n < 1 || k < 1) return -1;
list <int> list_loop; // 用std::list 模拟循环链表
for (int i = 0; i < n; ++i) { // 初始创建链表
list_loop.push_back(i);
}
list<int>::iterator p = list_loop.begin(); // 链表头
while (list_loop.size() != 1) { // 没有删到只剩最后一个数
for (int i = 1; i < k; ++i) { // p找到当前要删的元素
++p;
if (p == list_loop.end()) {
p = list_loop.begin(); // 循环
}
}
list<int>::iterator p_next = ++p; // 用p_next缓存下一个元素,不能p_next = p+1
--p; // list 迭代器没有重载操作符 +,- 只能赋值
list_loop.erase(p);
p = p_next;
if (p == list_loop.end()) p = list_loop.begin(); // 不要忘了处理
// for (list<int>::iterator io = list_loop.begin(); io != list_loop.end();++io) {
// printf(" %d ", (*io));
// }
}
return list_loop.front();
}
方法2. 数学推导递归
n > 1 : f(n)= (f(n-1)+ m )% n;
n = 1: f(n) = 0
请参考这里
int ysfdg(int n, int m) {
if (n == 1)
return 0;
else
return (ysfdg(n - 1, m) + m) % n; // m是固定的,f函数里完全可以不带m,
//不要被书上303页带m的式子唬住
}
int ysf(int n, int m) {
if (n < 1 || m < 1) return -1;
else return ysfdg(n, m);
}