剑指offer 之 约瑟夫环(孩子们的游戏,圆圈中最后剩下的)

约瑟夫环这道题做了很多次,但每次重新看的时候都感觉自己失忆了,所以这次必须记录一下!!!

题目

(来自牛客)

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

如果没有小朋友,请返回-1

思路

先给出一个例子,n=9,m=3,每次删除编号为2的数据,通过8轮报数,最后余下编号为0的数据。

剑指offer 之 约瑟夫环(孩子们的游戏,圆圈中最后剩下的)_第1张图片

题目问的是最后剩下的元素,那么最后一轮只有一个元素,在当前轮它对应的编号为0。我们怎么把它倒退回第一轮呢?这里需要考虑清楚的主要有两点:

1. 我们每一轮删除的元素索引。

2. 本轮索引与下一轮索引之间的转换关系,只有知道了两轮元素之间的对应关系,我们才能找到某一轮任意元素在上一轮中的编号。


首先来看第一点,考虑两种情况:

-- 当n>m时,很明显,我们直接删除编号为m-1的索引就可以了;

-- 当n

这两种情况合并起来,删除的元素索引为m%n-1。(n>m时,m%n-1=m-1)


再来看第二点,本轮索引与下一轮索引的关系,我这里列出了n个元素中删除第m个元素前后两轮索引的转换关系,看下图:

也就是说,删除第m%n-1个元素后,在新一轮的循环中原来编号为m%n的元素现在编号是0,因为删除了一个元素,所以剩余总元素为n-1个,新编号与原来编号的转换关系为:(新编号+m)%n=原编号。注意:这里的n是每一轮数据个数,并不是题目里所说的n。


现在是不是很清晰了:

1. 最后剩下的元素索引为0

2. 根据每两轮之间元素的对应关系,通过n-1轮循环,找到这个元素的原始索引。

代码

# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
        if n <=0 or m <= 0:    # 不要忘记特殊情况哦
            return -1
        index = 0 # 最后只剩一个孩子时,编号为0
        for i in range(2, n+1):
            index = (index+m) % i   # 这里的i代表每轮元素的个数
        return index

 

你可能感兴趣的:(剑指offer)