目录
剑指 Offer 62. 圆圈中最后剩下的数字
题目背景:
题解:
代码:
结果:
剑指 Offer 62. 圆圈中最后剩下的数字
题目背景:
这是著名的约瑟夫环问题
这个问题是以弗拉维奥·约瑟夫命名的,他是1世纪的一名犹太历史学家。他在自己的日记中写道,他和他的40个战友被罗马军队包围在洞中。他们讨论是自杀还是被俘,最终决定自杀,并以抽签的方式决定谁杀掉谁。约瑟夫斯和另外一个人是最后两个留下的人。约瑟夫斯说服了那个人,他们将向罗马军队投降,不再自杀。约瑟夫斯把他的存活归因于运气或天意,他不知道是哪一个。
—— 【约瑟夫问题】维基百科
题解:
约瑟夫环问题的三种解法讲解 - 力扣(LeetCode)
将数据放在数组里,在数组后面加上了数组的复制,以体现是环状的
第一轮是 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] 。这一轮 2被 删除了。
第二轮是 [3, 4, 0, 1, 3, 4, 0, 1] 。这一轮 0 被删除了。
第三轮是 [1, 3, 4, 1, 3, 4] 。这一轮 4 被删除了。
第四轮是 [1, 3, 1, 3] 。这一轮 1 被删除了。
最后剩下3,下标是 0。
第四轮反推,补上 m 个位置,然后模上当时的数组大小 2
位置是(0 + 3) % 2 = 1。第三轮反推,补上 m 个位置,然后模上当时的数组大小 3
位置是(1 + 3) % 3 = 1。第二轮反推,补上 m 个位置,然后模上当时的数组大小 4
位置是(1 + 3) % 4 = 0。第一轮反推,补上 m 个位置,然后模上当时的数组大小 5
位置是(0 + 3) % 5 = 3。所以最终剩下的数字的下标就是3。因为数组是从0开始的,所以最终的答案就是3。
总结一下反推的过程,就是 (当前index + m) % 上一轮剩余数字的个数。
代码:
class Solution { public int lastRemaining(int n, int m) { int ans=0; //(index+m)%上一轮剩余数字的个数 //倒着推得出结果前肯定还剩两个数,所以从i=2开始 for(int i=2;i<=n;i++){ ans=(ans+m)%i; } return ans; } }
结果: