在几乎无限的列表中查找元素

时间:2019-06-24 14:30:46

标签: python algorithm math implementation

我正在尝试解决此问题:

  

列表被初始化为["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)

如何更快地做到这一点?

3 个答案:

答案 0 :(得分:2)

这是在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。但是,您必须首先找出发生这种情况的次数。这就是一阵子在做什么(n = n - len(l)* (2**i)在做什么)。当意识到实现重复列表的i次后,while停止。最后,找出i之后,必须计算索引。但是在第i个附加列表中,每个元素都被复制了2^i次,因此您必须将数字指定为2**i。一个较小的细节是对于索引,您必须减去1,因为Python的列表是0索引的,而输入是1索引的。

答案 1 :(得分:0)

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

要了解这一点,请注意,如果您从一个5个人的列表开始并执行5个迭代步骤,那么您将获得与以前相同的顺序,只是每个人都两次。

我不是100%肯定n位置会一直移动,这是什么意思,但是如果您的意思是n次迭代后在前面的人,请求解满足的最大整数

    //Max is the value, Key is the index
    Map<Integer, Integer> m = new HashMap<>();

    int [] a={10,20,30,40,40};

    int max=a[0];

    for(int i=0;i<a.length;i++)
    {
        if(a[i] >= max)
        {
            max=a[i];
            //If the value is not inside the map, empty the map
            if (!m.containsValue(max))
            {
                m.clear();
            }
            //Place the value into the map
            m.put(i, max);
        }
    }
    System.out.print(m.toString());

以获得列表加倍的次数。然后只需查看其余列表(每个名字都会被提及i次),即可将其命名为n-5 * 2 ^ i。

答案 2 :(得分:-1)

您将无法避免计算列表,但是也许可以使它更容易一些:

每个周期(再次出现sheldon时),列表的长度都会增加一倍,因此看起来像这样:

1个周期后:SSLLPPRRHH

2个周期后:SSSSLLLLPPPPRRRRHHHHH

...

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

因此,您可以在最接近结束的周期计算列表的状态。 例如。 可乐编号50:

5 *((2 ** 3))= 40表示谢尔顿在排入40位可乐之后。

然后,您可以使用任务中描述的算法,并获得该行中的最后一个算法。

希望这会有所帮助。