【剑指 Offer 62. 圆圈中最后剩下的数字】
题目描述:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/
- 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:
- 参考k神解析.
- “约瑟夫环” 问题,学习使用 动态规划 解决。
- 即是后一步的结果需要使用前一步的数值。
- 对于「n,m 问题」,首轮删除环中第 m 个数字后,得到一个长度为 n−1 的数字环。由于有可能m>n ,因此删除的数字为 (m−1)%n ,删除后的数字环从下个数字(即 m%n )开始,设t=m%n ,可得数字环:
- f(n) 可由 f(n - 1)得到,f(n−1) 可由 f(n−2) 得到,……,f(2) 可由 f(1) 得到;因此,若给定 f(1) 的值,就可以递推至任意 f(n) 。而「1, m 问题」的解 f(1) = 0 ,即无论 m 为何值,长度为 1 的数字环留下的结果一定是数字 0 。
- 算法流程示意图:
- 动态规划算法:
- 设定初始的状态参数 + 推得状态转移方程
- 1、设定 【i,m】的变量值为 res[i]、【1,m】的值恒为 0 ;
- 2、状态转移方程: res[ i ] 的结果由 res[ i-1 ] 递推得到:
-
res[ i ] = ( res[ i-1 ] + m) % n
- 3、返回值 :【n,m】问题的变量值 res[n];
代码(python3)
class Solution:
def lastRemaining(self, n: int, m: int) -> int:
res = 0;
for num in range(2,n+1):
res = (res + m ) % num;
return res;
代码(cpp)
class Solution {
public:
int lastRemaining(int n, int m) {
int res = 0;
for (int i=2; i<=n; i++){
res = (res + m) % i;
}
return res;
}
};
复杂度分析:
- 时间复杂度 O(n):状态转移循环n−1 次使用 O(n) 时间,状态转移方程计算使用 O(1) 时间;
- 空间复杂度 O(1) : 使用常数大小的额外空间