题目描述
共有 n 名小伙伴一起做游戏。小伙伴们围成一圈,按 顺时针顺序 从 1 到 n 编号。确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1 <= i < n ,从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。
游戏遵循如下规则:
从第 1 名小伙伴所在位置 开始 。
沿着顺时针方向数 k 名小伙伴,计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数,一些小伙伴可能会被数过不止一次。
你数到的最后一名小伙伴需要离开圈子,并视作输掉游戏。
如果圈子中仍然有不止一名小伙伴,从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始,回到步骤 2 继续执行。
否则,圈子中最后一名小伙伴赢得游戏。
给你参与游戏的小伙伴总数 n ,和一个整数 k ,返回游戏的获胜者。
示例 1:
输入:n = 5, k = 2
输出:3
解释:游戏运行步骤如下:
1) 从小伙伴 1 开始。
2) 顺时针数 2 名小伙伴,也就是小伙伴 1 和 2 。
3) 小伙伴 2 离开圈子。下一次从小伙伴 3 开始。
4) 顺时针数 2 名小伙伴,也就是小伙伴 3 和 4 。
5) 小伙伴 4 离开圈子。下一次从小伙伴 5 开始。
6) 顺时针数 2 名小伙伴,也就是小伙伴 5 和 1 。
7) 小伙伴 1 离开圈子。下一次从小伙伴 3 开始。
8) 顺时针数 2 名小伙伴,也就是小伙伴 3 和 5 。
9) 小伙伴 5 离开圈子。只剩下小伙伴 3 。所以小伙伴 3 是游戏的获胜者。
示例 2:输入:n = 6, k = 5
输出:1
解释:小伙伴离开圈子的顺序:5、4、6、2、3 。小伙伴 1 是游戏的获胜者。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-winner-of-the-circular-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
看到这题时,我的思路是一种比较笨的方法,就是用一个布尔类型的flag数组,标记每一个人的状态,初始时每个人都为True,当在第一轮游戏中被选中时,将这个人对应位置处的flag标记为False,表示这个人失败了,因为标记为失败之后,就可以在后续的遍历中,通过该标记位知道这个人已经从游戏中退出,可以看作逻辑删除这名玩家,就可以跳过这个人,进而寻找顺时针k个位置的下个失败者,直到游戏只有一个人存在时,start中记录的即为获胜者的编号。
实现起来,时间复杂度非常的高,达到了O(nk)量级,因为对每一个人,都要进行k步的模拟寻找下一个符合条件的失败者。这种方法不仅时间复杂度高,而且数组的下标很容易出现越界,改了三次才成功通过,最后的用时1800+ms属实是让我蚌埠住了。
参考题解之后,我发现大可不必如此大费周章的遍历,寻找失败者,只要动态的更新玩家数组就可以了。用一个数组存储1-n名玩家的编号,start=0初始位置,更新时loser=(start+k-1)%len(ans),表示失败者的位置,另外还要更新下一轮游戏起始者的位置start=loser if loser!=len(ans)-1 else 0,就是说如果当前轮求出的失败者不是位于所剩玩家数组的最后一个,就让起始位置为刚才求出的失败者的位置,因为要接下来要删除改位置处的失败者,相当于让失败者后一个人当下轮游戏的开始者,但如果失败者已经是当前数组的最后一人,那么由于求余的性质,肯定是下标为0的人是当前失败者的后一个人,就让下轮游戏的开始者为0即可,做完以上两步更新操作后,就可以放心的把当前求出的本轮游戏失败者从玩家数组中删除了。删除之后动态的维护这个玩家数组,每轮游戏失去一个失败者,直到最后数组中只有一人时,就是要求的答案。
代码实现
1.我的实现思路:模拟依次遍历
class Solution:
def findTheWinner(self, n: int, k: int) -> int:
flag=[True for i in range(n+1)]
round=1
start=1
while round<n:
i=1
while i<k :
if flag[start%n+1]:
i+=1
start=start%n+1
flag[start]=False
while flag[start]==False:
start=start%n+1
round+=1
return start
2.参考的思路:直接计算
class Solution:
def findTheWinner(self, n: int, k: int) -> int:
start,ans=0,[i for i in range(1,n+1)]
while len(ans)>1:
loser=(start+k-1)%len(ans)
start=loser if loser!=len(ans)-1 else 0
del ans[loser]
return ans[0]