剑指 Offer 62. 圆圈中最后剩下的数字
题目描述:
0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例:
输入: n = 5, m = 3
输出: 3
输入: n = 10, m = 17
输出: 2
思路:
思路①:创立数组,每当到m-1位置时,删除数组中元素,然后将位置计0重新开始
思路②:
- n个人编号0,1,2,…,n-1,每数m次删掉一个人
- 假设有函数f(n)表示n个人最终剩下人的编号
- n个人删掉1个人后可以看做n-1的状态,不过有自己的编号。
- n个人删掉的第一个人的编号是(m-1)%n,那么n个人时删掉第一个人的后面那个人(m-1+1)%n一定是n-1个人时候编号为0的那个人,即n个人时的编号m%n(这个编号是对于n个人来考虑的),n-1个人时编号为i的人就是n个人时(m+i)%n
- 所以f(n)=(m+f(n-1))%n
- f(1)=0,因为1个人时只有一个编号0。因此可以将人数从2反推到n
思路②(另一种解释):
在这 n个数字中, 第一个被删除的数字是(m-1)%n。为了简单起见,我们把(m- 1)%n 记为 k,那么删除k之后剩下的 n-1 个数字为 0,1,… ,k-1,k+1,… ,n-1,并且下一次删除从数字 k+1 开始计数。相当于在剩下的序列中, k+1 排在最前面,从而形成 k+1,… ,n- 1,0,I,… ,k-1 。该序列最后剩下的数字也应该是关于 n 和 m 的函数。由于这个序列的规律和前面最初的序列不一样(最初的序列是从 0 开始的连续序列),因此该函数不同于前面的函数,记为 f’(n-1,m)。最初序列最后剩下的数字 f(n, m)一定是删除一个数字之后的序列最后剩下的数字,即 f(n, m)=f’(n-1, m)。
接下来我们把剩下的这 n-1 个数字的序列 k-1, …,n-1,0,1,… ,k-1 做一个映射,映射的结果是形成一个从 0 到 n-2 的序列:
代码:
思路①:
1 | var lastRemaining = function(n, m) { |
思路②:
1 | var lastRemaining = function(n, m) { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Jungle!