剑指 Offer 62. 圆圈中最后剩下的数字 (约瑟夫问题)

题目

0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

示例 1:

输入: n = 5, m = 3
输出: 3

示例 2:

输入: n = 10, m = 17
输出: 2

限制:
1 <= n <= 10^5
1 <= m <= 10^6

解题思路

  1. 使用列表模拟叫号、删除数字的过程
    如n=5, m=3
    下表下划线元素,为每次删除的元素,一次删除一个。
原始数据 0 1 2 3 4
第1次删除 0 1 2 3 4
剩余元素位置左移 0 1 3 4
第2次删除 0 1 3 4
剩余元素位置左移 1 3 4
第3次删除 1 3 4
剩余元素位置左移 1 3
第4次删除 1 3
剩余元素位置左移 3

注意到第i次删除操作,删除元素位置都是 (i + m -1 ) % n, n是当前元素个数(表长);
如果使用java编程,可以使用ArrayList自动维护 “剩余元素位置左移” 的操作。

伪码

lastRemaining(N, m)
      // 新建list 
      let list[0..n-1] = 0,1,2,...,n-1
      i = 0
      while list.size > 1 
            i = (i + m - 1) % list.size
            list.remove( i )
return list[0]
  1. 考虑第k次删除,和第k-1次删除之间的数学关系
位置 0 1 2 ... m-2 m-1 m m+1 ... n-1
第k-1次操作后 a0 a1 a2 ... a(m-2) a(m-1) a(m) a(m+1) ... a(n-1)
第k次删除 a0 a1 a2 ... a(m-2) a(m-1) a(m) a(m+1) ... a(n-1)
左移剩余元素 a(m) a(m+1) ... a(n-1) a0 a1 a2 ... a(m-2)

第k删除的元素的位置为 (m-1) % n, n = N-k,其中,N是元素初始个数,n是当前剩余元素个数(第k-1次操作后)。
相当于在第k-1次删除后的基础上,a[m..n-1]元素都往左移m个位置,a[0..m-2]右移 n-1 - m + 1 = n - m个元素。
 
记f(i, k),表示初始位置为i的元素,经历k次操作后的位置(前提是前k-1次,该元素都未被删除),有

[f(i,k)= egin{cases} f(i, k-1) - m& ext{f(i, k-1) > m-1}\ f(i, k-1) + n - m& ext{f(i, k-1) < m-1} end{cases}]

上式可以综合到一起,

[f(i,k)= [f(i, k-1) - m] \% n], 其中, f(i, k-1) ≠ m-1,n = N - (k-1) ]

已知什么,要求什么?
已知的是第k次删除元素后,只剩1个元素位置为0,即为所求元素。
也就是说,已知f(k=N-1) = 0,要求f(0),而a[f(0)]即为所求元素值。把f(k-1)写成f(k)的表达式。
推导过程,

[∵f(k) = [f(k-1)-m] \% n, n = N - (k-1)\ ∴f(k-1) - m = xn + f(k), x∈Z\ ∴f(k-1) = xn + f(k) + m, 式子两边对n求余, 有\ f(k-1) \% n = [f(k) + m] \% n, 而f(k-1)就是元素在长度为n(n=N-(k-1))时的位置,\ 也就是说, f(k-1)∈[0, n) \ 故f(k-1) = f(k-1) \% n = [f(k) + m] \% n \ ]

问题转化为

[f(k=N-1) = 0 \ f(k-1) = [f(k) + m] \% 2 \ f(k-2) = [f(k-1) + m] \% 3 \ ...\ f(1) = [f(0) + m] \% (N-1) \ f(0) = [f(1) + m] \% (N) ]

这样,就可以利用程序进行循环/递归求解了。
伪代码

lastRemaining(N, m)
      k = N - 1
      pos = 0
      while k > 0
            pos= (pos + m) % (N - k + 1)
            k = k-1
      return pos

参考

剑指 Offer 62. 圆圈中最后剩下的数字

原文地址:https://www.cnblogs.com/fortunely/p/14227676.html