找到Python中活着人数最多的年份

osk*_*i86 10 python algorithm

鉴于人用自己的出生和结束年(所有之间的名单19002000),寻找当年数最多的人活着.

这是我有点蛮力的解决方案:

def most_populated(population, single=True):
    years = dict()
    for person in population:
        for year in xrange(person[0], person[1]):
            if year in years:
                years[year] += 1
            else:
                years[year] = 0
    return max(years, key=years.get) if single else \
           [key for key, val in years.iteritems() if val == max(years.values())]

print most_populated([(1920, 1939), (1911, 1944),
                      (1920, 1955), (1938, 1939)])
print most_populated([(1920, 1939), (1911, 1944),
                      (1920, 1955), (1938, 1939), (1937, 1940)], False)
Run Code Online (Sandbox Code Playgroud)

我正试图找到一种更有效的方法来解决这个问题Python.两者 - readabilityefficiency计数.此外,由于某些原因,我的代码将不会打印[1938, 1939].

更新

输入是一个list元组,其中元组的第一个元素是year人出生时的元素,而第二个元素tuple是死亡年份.

更新2

结束一年(元组的第二部分)和一个人活着的一年(所以如果这个人死了Sept 1939(我们不关心这个月),他实际上是在1939年活着,至少是其中的一部分) .这应该可以解决1939年的结果缺失问题.

最佳方案?

虽然可读性有利于@joran-beasley,但对于更大的输入,最有效的算法由@ njzk2提供.感谢@ hannes-ovrén 在Gist上IPython笔记本提供分析

njz*_*zk2 5

我只是的另一种解决方案:

  • 创建2个表,birthdates然后deathdates
  • 在这些表中累积出生日期和死亡日期。
  • 浏览这些表以累积当时的活人数量。

总的复杂度是 O(n)

实作

from collections import Counter

def most_populated(population, single=True):
    birth = map(lambda x: x[0], population)
    death = map(lambda x: x[1] + 1, population)
    b = Counter(birth)
    d = Counter(death)
    alive = 0
    years = {}
    for year in range(min(birth), max(death) + 1):
        alive = alive + b[year] - d[year]
        years[year] = alive
    return max(years, key=years.get) if single else \
           [key for key, val in years.iteritems() if val == max(years.values())]
Run Code Online (Sandbox Code Playgroud)

更好

from collections import Counter
from itertools import accumulate
import operator

def most_populated(population, single=True):
    delta = Counter(x[0] for x in population)
    delta.subtract(Counter(x[1]+1 for x in population))
    start, end = min(delta.keys()), max(delta.keys())
    years = list(accumulate(delta[year] for year in range(start, end)))
    return max(enumerate(years), key=operator.itemgetter(1))[0] + start if single else \
           [i + start for i, val in enumerate(years) if val == max(years)]
Run Code Online (Sandbox Code Playgroud)


Jor*_*ley 4

>>> from collections import Counter
>>> from itertools import chain
>>> def most_pop(pop):
...     pop_flat = chain.from_iterable(range(i,j+1) for i,j in pop)
...     return Counter(pop_flat).most_common()
...
>>> most_pop([(1920, 1939), (1911, 1944), (1920, 1955), (1938, 1939)])[0]
Run Code Online (Sandbox Code Playgroud)

  • 这就是我昨天想尝试的(提供更大的兰特测试数据),但已经是凌晨了。我不确定是否要更改已接受的答案,但我有一个想法,我将更新问题中的内容,为输入的小数据和大数据分别提供获胜的解决方案。 (2认同)