剑指offer第二版(Python3)--面试题62 : 圆圈中最后剩下的数字

第2章 面试需要的基础知识

第3章 高质量的代码

第4章 解决面试题的思路

第5章 优化时间和空间效率

第6章 面试中的各项能力

  面试题62 : 圆圈中最后剩下的数字

  面试题64 : 求1+2+3+…+n

第7章 两个面试案例


题目描述

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

解题思路
  实际上就是动态规划,只是这个递推式太难找了。

f(n, m)表示长度为n的序列,删除n-1次,最后留下元素的序号;

则f(n-1, m)表示长度为n-1的序列,删除n-2次,最后留下元素的序号;

我们知道 f(n, m)第一次删(m-1)%n,留下以((m-1)%n + 1)%(n-1)开头,长n-1的序列;

而f(n-1, m)留下元素的序号以0开头,因此两者的序号相差m个距离 f(n, m) = (f(n-1, m) + m) % n

具体可看LeetCode题解
实战

class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
        # n表示序列长度
        if n < 1 or m < 1:
            return -1
        
        last = 0
        for i in range(2, n+1):
            last = (last + m) % i
        return last

代码中循环为什么是从2到n呢?不应该是从n到2吗?
从递推式 f(n, m) = (f(n-1, m) + m) % n 可知,我们是已知 f(n-1, m) 求解 f(n, m)的。显然已知条件是 f(1, m) = 0,从已知条件推导 f(2, m),逐步递推就得到最后的 f(n, m)。
DP算法的特点是分析问题的顺序和求解顺序相反。

你可能感兴趣的:(算法设计)