这个是学习编程时的一个耳熟能详的问题了:
n
个人(编号为0,1,...,n-1
)围成一个圈子,从0
号开始依次报数,每数到第m
个人,这个人就得自杀,之后从下个人开始继续报数,直到所有人都死亡为止。问最后一个死的人的编号(其实看到别人都死了之后最后剩下的人可以选择不自杀……)。
这个问题一般有两种问法:
- 给出自杀顺序。不少数据结构初学书都会以这个问题为习题考验读者对线性表的掌握。比较常见的解法是把所有存活的人组织成一个循环链表,这样做时间复杂度是
O(n*m)
的。另外可以使用order statistic tree(支持查询第k小的元素以及询问元素的排名)优化到O(n log n)
。另外有篇1983年的论文An O(n log m) Algorithm for the Josephus Problem,但可惜我没找到下载链接。 - 求出最后一个人的编号。可以套用上一种问法的解法,但另外有更加高效的解法,下文展开讨论。