题目: n个数字 (0,1,2,3, ... , n-1) 形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字。
第一个为当前数字本身,第二个为当前数字的下一个数字。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字
此题目的另一种表述是:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
此题目也叫约瑟夫环问题,是一个非常经典的问题,我认为此题意在考察面试者对于算法和数据结构的理解,
因为这道题既可以从算法角度解决,也可以从数据结构的角度寻找思路
上面这个例子,就是有9个人,每数5个人,就排除出去,最后会剩下8号
我们假设是编号是从1开始计数的
先从数据结构的角度思考:
为了以一种循环方式排列人群,构建一个循环链表,每个人与他下一个人之间有一个链接。整数 i 表示循环中的第 i 个人。生成一个唯一节点的循环链表之后,
在该节点后插入2到n节点。
#include<stdio.h>
#include<stdlib.h>
struct node {
int id;
struct node* next;
};
int josephus(int n, int m) {
struct node* t = malloc(sizeof(struct node));
struct node* x = t;
t->id = 1;
t->next = t;
//构造循环链表并赋值
int i;
for(i=2; i<=n; i++) {
x = (x->next = malloc(sizeof(struct node)));
x->id = i;
x->next = t;
}
//不断从这个链表中删除节点,直到剩下最后一个
while(x != x->next) {
for(i=1; i<m; i++)
x=x->next;
x->next = x->next->next;
n--;
}
return x->id;
}
int main() {
printf("%d\n",josephus(9,5));
}
从算法角度考虑分为递归和非递归解决的方法:
本人愚钝,一直没有看懂这两种方法,但是先列出来吧,大家参考一下
递归的
int f(int n, int m)
{
if (n > 1)
return (m + f(n - 1, m)) % m;
else
return 0;
}
非递归的
int f(int n, int m)
{
int i, r = 0;
for (i = 2; i <= n; i++)
r = (r + m) % i;
return r+1;
}