【问题标题】:Find the element in virtually infinite list在几乎无限列表中查找元素
【发布时间】:2019-06-24 14:30:46
【问题描述】:

我正在尝试解决这个问题:

一个列表初始化为["Sheldon", "Leonard", "Penny", "Rajesh", "Howard"],然后进行一系列操作。在每个操作中,列表的第一个元素被移动到列表的末尾并复制。例如,在第一个操作中,列表变为["Leonard", "Penny", "Rajesh", "Howard", "Sheldon", "Sheldon"]"Sheldon" 被移动和复制);在第二次操作中,它变为["Penny", "Rajesh", "Howard", "Sheldon", "Sheldon", "Leonard", "Leonard"](“Leonard”被移动和复制);等等。给定一个正整数n,找出在第n次操作中被移动和复制的字符串。 [转述自https://codeforces.com/problemset/problem/82/A]

我已经写了一个可行的解决方案,但是当 n 很大时它太慢了:

l = ['Sheldon','Leonard','Penny','Rajesh','Howard']
n = int(input()) # taking input from user to print the name of the person
                 # standing at that position

 for i in range(n):
    t = l.pop(0)
    l.append(t)
    l.append(t)

    #debug
    # print(l)

print(t)

我怎样才能更快地做到这一点?

【问题讨论】:

  • 您可以在不实际生成列表的情况下找出答案。将每个名称加倍一次将使列表的长度加倍。您可以计算出需要将列表翻倍的次数,然后推断此时列表的结构。
  • @khelwood 你能详细说明一下吗?
  • @Aman 你在找人帮你解决这个问题吗? khelwood 给了你一个巨大的提示,如果你想自己解决它,它应该会对你有所帮助。
  • @Code-Apprentice 从那时起我一直在关注 khelwoods 的提示并尝试解决。我只是一个初学者,这就是为什么我需要时间
  • @Aman 即使不是初学者,解决问题也需要时间

标签: python algorithm math implementation


【解决方案1】:

这是一个在O(log(input/len(l))) 中运行的解决方案,无需进行任何实际计算(无列表操作):

l = ['Sheldon','Leonard','Penny','Rajesh','Howard']
n = int(input()) # taking input from user to print the name of the person
                 # standing at that position

i = 0
while n>(len(l)*2**i):
    n = n - len(l)* (2**i)
    i = i + 1

index = int((n-1)/(2**i ))

print(l[index])

解释:每次你推回整个列表时,列表长度会增加len(l) x 2^i。但是你必须首先找出这种情况发生了多少次。这就是 while 正在做的事情(这就是 n = n - len(l)* (2**i) 正在做的事情)。当它意识到i 将发生追加双列表的次数时,while 停止了。最后,在您计算出i 之后,您必须计算索引。但是在i-th 附加列表中,每个元素都被复制2^i 次,因此您必须将数字除以2**i。一个小细节是,对于索引,您必须减去 1,因为 Python 中的列表是 0 索引的,而您的输入是 1 索引的。

【讨论】:

    【解决方案2】:

    正如@khelwood 所说,您可以推断出您必须将列表翻倍。

    要理解这一点,请注意,如果您从 5 个人的列表开始并执行 5 个迭代步骤,您将与之前的顺序相同,只是每个人都在其中两次。

    我不是 100% 确定你对第 n 个位置的意思是什么,因为它一直在移动,但如果你指的是经过 n 次迭代后排在前面的人,请求解满足的最大整数 i

    5*2^i<n 
    

    获取您的列表翻倍的次数。然后只需查看剩余的列表(每个名称都被提及 i 次)以获取位置 n-5*2^i 的名称。

    【讨论】:

      【解决方案3】:

      你将无法避免计算列表,但也许你可以让它更容易一点:

      每个循环(当 Sheldon 再次成为第一个时)列表的长度增加了一倍,所以它看起来像这样:

      1 个周期后:SSLLPPRRHH

      2 个周期后:SSSSLLLLPPPPRRRHHHH

      ...

      而他们喝的可乐数量是 5*((2**n)-1),其中 n 是循环次数。

      因此您可以在最近结束的循环中计算列表的状态。 例如。 50 号可乐:

      5*((2**3)) = 40 表示在 40 杯可乐之后 sheldon 排在下一个。

      然后你可以使用任务中描述的算法,得到最后一个。

      希望这会有所帮助。

      【讨论】:

      • 我建议你阅读,如何回答问题。这肯定会有所帮助
      • 请注意,您的建议避免计算整个列表。您可以使用一些数学来尽可能多地跳过循环。
      • 我建议您欣赏比您的解决方案更有效的解决方案。我知道它并没有真正写出来,但老实说,阅读你的问题几乎让我中风,所以不要谈论写作
      猜你喜欢
      • 2018-12-11
      • 2011-01-12
      • 2016-07-18
      • 2015-02-07
      • 1970-01-01
      • 1970-01-01
      • 2015-12-24
      • 2011-04-05
      • 2017-06-14
      相关资源
      最近更新 更多