题目描述
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
1 | 输入: n = 5, m = 3 |
示例 2:
1 | 输入: n = 10, m = 17 |
限制:
- $1 <= n <= 10^5$
- $1 <= m <= 10^6$
算法 1
(模拟环形链表) $O(nm)$ 超时
用 $list$ 模拟环形链表,由于 $list$ 不是环形结构,所以当迭代器走到链表末尾时,需要让其转到链表头部形成环
每次从迭代器指向的数开始数,数 $m$ 次找到第 $m$ 个数,将其删除,接着再从下一个位置开始数,循环此过程,直到环中只剩下一个数,就是答案
时间复杂度
环中总共有 $n$ 个数字,需要删掉 $n - 1$ 个数才能得到答案,每删除一个数需要迭代器移动 $m - 1$ 次,所以时间复杂度为 $O(nm)$
空间复杂度
$O(n)$
参考文献
https://www.ac_wing.com/solution/content/796/
C++ 代码
1 |
|
算法 2
(推导递推式) $O(n^2)$
首先我们应该知道 $f[i, m]$ 的含义是 $i$ 个数字中删除第 $m$ 个数字
$f(n, m)$ 表示 $n$ 个数字删除第 $m$ 个数字,删除 $m - 1$,此时圆中的数字为 $(0, 1, 2, … m - 2, m, m + 1 .. n - 1)$ (m - 1 被删掉了)
$f(n - 1, m)$ 表示 $n - 1$ 个数字中删除第 $m$ 个数字,开始数数前此时圆中的数字为 $(m, m + 1, m + 2 … n - 1, n[0], n + 1[1], n + 2[2]…) % n$
观察两组数字,可得递推式:f(n, m) = (f(n - 1, m) + m) % n
边界:当 n = 1
时圆中只有一个数字 $0$,返回 $0$ 即可
时间复杂度
由 $f[1, m] = 0$ 递推 $n - 1$ 次就可以得到 $f[n, m]$,所以时间复杂度为 $O(n)$
C++ 代码
1 | class Solution { |