问题
模拟求解流程
设 n = 5, m = 3
n = 5, 0, 1, 2, 3, 4 => 0, 1, 2, 3, 4
n = 4, 3, 4, 0, 1 => 3, 4, 0, 1
n = 3, 1, 3, 4 => 1, 3, 4
n = 2, 1, 3 => 1, 3
n = 1, 3 => END
由于每趟从被删除元素之后开始数,我把被删除的元素都移到数组中的第一个位序。
那么,可以观察到被删除的总是下标为
(0 + m) mod n
的元素;
删除元素后,其他的元素都向前移动了m
位,最终坐落在坐标为(idx - m) mod (n -1)
的位置上(idx为元素未移动前的坐标)
依照上面的话, 我们只需要知道某个数的坐标就能反推出该数在上一趟的坐标。
自下而上推导
由上述的求解流程,我们可以肯定的是最后一趟(即n=1时), 只有一个数,而且其坐标一定为0
假设idx1的意思是解在剩余n人时的坐标位置。
已知 idx1 = 0
由于相比上一趟所有元素都移动了3位,那么应该往后挪3位才能推到原来的位置上。
因此,
idx2 = (idx1 + 3) mod 2 = (0 + 3) mod 2 = 1
idx3 = (idx2 + 3) mod 3 = (1 + 3) mod 3 = 1
idx4 = (idx3 + 3) mod 4 = (1 + 3) mod 4 = 0
idx5 = (idx4 + 3) mod 5 = (0 + 3) mod 5 = 3
答案呼之欲出 😃
因此,只有5个元素时,最后剩下的一定是坐标为3的元素。
推导出一般方程
i
d
x
n
=
(
i
d
x
n
−
1
+
m
)
m
o
d
n
(
n
≥
1
)
idx_n = (idx_{n-1} + m) \space mod \space n \space\space (n \ge 1)
idxn=(idxn−1+m) mod n (n≥1)
代码实现
def GetFinalIndex(n: int, m: int) -> int:
idx = 0
k = 2
while k != n + 1:
idx = (idx + m) % k
k += 1
return idx