剑指Offer解题报告(Java版)——约瑟夫环 45

   

引言

   

常见的约瑟夫环问题有用循环链表做的,有用数组做的,这里提供一个用数学公式做的,由此可见,很多计算机的问题如果最终用到数学的知识,时间复杂度会大大的降低

   

分析问题

   

首先我们对0n-1删除第一个数进行分析,第一个被删除的数一定是序号为m-1的数,因为0号数了1,1号数了2,m-1号数了m,那么应该删掉m-1号,设m-1号是第k号,这里这样做是因为后面可以扩展,想扩展为m-1%n=k

   

剩下的数按照序列重排序如下

   

因为删掉的是k,那么下面第一个就是k+1了,这个很好理解

   

假设我们设f函数的输出是原来的在n个数中,每次数m下,最后留下的数

   

而现在删掉了k,只有n-1个数了,每次数m下,最后留下的数是f'(n-1,m)

   

   

如何建立ff'之间的关系呢

   

我们对重排序之后的数做一个映射

   

   

该映射为

p(x) -- > y ::: y=(x-k-1)%n

   

则映射完之后就跟原来的问题一样了,也就是f(n-1,m)了

   

也就是p(f'(n-1,m)=f(n-1,m)

   

而我们现在只有f(n,m)和f'(n-1,m)之间的关系

   

所以我们还需要再转换一下,也就求映射的逆

   

   

而映射p的逆映射为

   

o(y) -- >x x=(y+k+1)%n

   

其中k可以替换 k%n=(m-1)%n

   

o(y) -- >x x=(y+m)%n

   

对应到之前f(n-1,m)f'(n-1,m)之间的关系

   

f'(n-1,m)=f(n-1,m)+m%n

   

   

f(n,m)=f'(n-1,m)

   

这样我们有f(n,m)f'(n-1,m)之间的关系,也有f(n-1,m)f'(n-1,m)之间的关系

   

带入之前的式子推到得到

   

   

解决问题

   

static int lastRemain(int n, int m) {

int last = 0;

if (n < 1 || m < 1) {

return -1;

}

for (int i = 2; i <= n; i++)

last = (last + m) % i;

return last;

}

   

posted @ 2015-05-03 19:38  keedor  阅读(431)  评论(0编辑  收藏  举报