您的位置:首页 > 理论基础 > 数据结构算法

数据结构和算法经典100题-第18题

2015-06-25 01:22 615 查看
这是一个约瑟夫环问题。Okay看题目吧。

第18题

题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,

每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。

当一个数字删除后,从被删除数字的下一个继续删除第m个数字。

求出在这个圆圈中剩下的最后一个数字。

题目分析:第一时间想到的方法是创建一个循环链表或者是一个带有循环数组这样一个循环数据结构来模拟整个过程。

代码可能是这样的:

int func(int n,int m) {
#define GO_ON if(i == n){i = 0;} else {i++;}
int i;

// assert
if (0 > m ) {
return -1;
}

// init circular array
int *array = (int*)malloc(sizeof(int)*n);
for (i = 0; i < n; i++) {
array[i] = i;
}

// define variable for ergodic
int removeNum = 0;// 环中剩余一个元素时结束
int tmp = 0; // 累加到m时,删除
i = 0;

// ergodic
while ( n -1 == removeNum) {
if (-1 == array[i]) {
GO_ON;
continue;
}

if (m == tmp) {
array[i] = -1;
removeNum--;
tmp = 0;
} else {
tmp++;
}

GO_ON;
}

return array[i];
}


OKay,but亲们这不是最简单的方法,从网络上看到一个解决这种类似的约瑟夫环问题更简单的算法:

f(n,m)={ 0 n=1

[f(n-1,m)+m]%n     n>1
}


感兴趣的亲们可以到这个网址看一下,推导的过程:

http://zhedahht.blog.163.com/blog/static/2541117420072250322938/

OK,有个这个递推公式,那么解决这个问题,不论是用迭代法还是递归法都很好解决了,下面给出本人根据以上公式写得代码:

int recursion(int n,int m)  {
if (0 == n) {
return 0;
}

return (recursion(n-1, m) + m) % n;
}

int foo(int n,int m) {
if (0 == n) {
return 0;
}
int k = 0;
for (int i = 1; i < n; i++) {
k = (k + m) % i;
}
return k;
}


Okay,路漫漫啊。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息