一、题目
0,1,···,n-1
这n
个数字排成一个圆圈,从数字0
开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如:0、1、2、3、4
这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1
,因此最后剩下的数字是3。
二、示例
2.1> 示例 1:
【输入】 n = 5, m = 3
【输出】 3
2.2> 示例 2:
【输入】 n = 10, m = 17
【输出】 2
限制:
1
<= n <=10^5
1
<= m <=10^6
三、解题思路
根据题目描述,我们会得到一个长度为n
的数组,然后这个数组会首尾相接从而组成一个圆圈。那么我们每次从这个圆圈里删除第m个数字,从而求出最后剩余的那个数字。我们以数组为[0,1,2,3,4]
,m=3
为例,具体的执行逻辑此处就不赘述了,请见下图所示即可:
那么,如果我们以模拟的方式去执行的话,由于n
的区间在[1, 10^5]
,m
的区间在[1, 10^6]
,所以会造成执行超时。如下面代码4.1> 采用模拟的方式实现
所示。
还有什么其他的解题方式呢?我们其实可以采用动态规划方式解答这道题。
以数组是[0,1,2,3,4]
为例,如上图所示,最终剩余的数字是3
,那么其实这道题也可以理解为:寻找数字3所在的下标位置。为什么这么说呢?我们以数组的方式,再次演示一下删除元素操作。当最后剩余数字3
的时候,当前元素个数是1个
,元素3
所在的位置index等于0
;而且,我们可以得出第一个结论:只要是剩余最后1个元素,其index一定是0;
那么,我们就从只有1
个元素向上推导有2
个元素,直到推导到5
个元素:
【总共有1个元素】
index1
=0
;【总共有2个元素】
index2
= (index1 + m) % 2 = (0 + 3) % 2 =1
;【总共有3个元素】
index3
= (index2 + m) % 3 = (1 + 3) % 3 =1
;【总共有4个元素】
index4
= (index3 + m) % 4 = (1 + 3) % 4 =0
;【总共有5个元素】
index5
= (index4 + m) % 5 = (0 + 3) % 5 =3
;
通过上面的推导,我们可以得出状态转移方程为:index = (index + m) % i,其中,i
表示总共有的元素个数。具体实现逻辑代码请见4.2> 采用动态规划方式实现
。
四、代码实现
4.1> 采用模拟的方式实现(会提交超时)
class Solution { public int lastRemaining(int n, int m) { Deque<Integer> queue = new ArrayDeque(); for (int i = 0; i < n; i++) queue.addLast(i); while(queue.size() > 1) { int count = m; while(count-- > 0) { Integer num = queue.removeFirst(); if (count != 0) queue.addLast(num); } } return queue.removeFirst(); } }
4.2> 采用动态规划方式实现
class Solution { public int lastRemaining(int n, int m) { int result = 0; for (int i = 2; i <= n; i++) result = (result + m) % i; return result; } }
今天的文章内容就这些了:
写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。
更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」