题目描述
解题思路
看到这题时,我的思路是一种比较笨的方法,就是用一个布尔类型的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]