是否有更简洁/ pythonic的方式来做到这一点? (计算头部最长的seq,硬币翻转的尾巴)

时间:2009-11-06 17:18:34

标签: python

计算200枚硬币翻转中最长的头尾序列 我这样做了 - 在python中有没有更快的方法呢? (没有太混淆)

import random

def toss(n):
    count = [0,0]
    longest = [0,0]
    for i in xrange(n):
        coinface = random.randrange(2)
        count[coinface] += 1
        count[not coinface] = 0

        if count[coinface] > longest[coinface]:
            longest[coinface] = count[coinface]      
        #print coinface, count, longest  

    print "longest sequence heads %d, tails %d" %tuple(longest)

if __name__ == '__main__':
    toss(200)

请参阅this了解我播放的内容

9 个答案:

答案 0 :(得分:11)

def coins(num):
    lst = [random.randrange(2) for i in range(num)]
    lst = [(i, len(list(j))) for i, j in itertools.groupby(lst)]
    tails = max(j for i, j in lst if i)
    heads = max(j for i, j in lst if not i)
    return {1: tails, 0: heads}

答案 1 :(得分:11)

import collections, itertools, random

def makesequence(choices=2, length=200):
  return [random.randrange(choices) for _ in itertools.repeat(None, length)]

def runlengths(sequence):
  runlength_by_item = collections.defaultdict(set)
  for key, group in itertools.groupby(sequence):
    runlength_by_item[key].add(sum(1 for _ in group))
  return dict((k, max(v)) for k, v in runlength_by_item.items())

正如您将注意到的,这更加“分离” - runlengths是确定任何可迭代中不同可清洗项目的最大运行长度的完全通用方法(如果您需要此类运行,则可高度重复使用)在各种不同的上下文中的长度),正如makesequence是一种完全通用的方法,可以根据列表长度和每个随机数的选择数来制作随机数列表。将这两者放在一起可能无法为给定的,高度具体的问题提供最佳的点解决方案,但它会接近,并且构建可重复使用的“构建块”的小库将比仅解决每个问题具有更高的长期回报。完全专用代码的具体问题。

答案 2 :(得分:7)

您可以使用itertools,这是更多Pythonic方式:

def toss(n):
    rolls = [random.randrange(2) for i in xrange(n)]
    maximums = [0, 0]
    for which, grp in itertools.groupby(rolls):
        maximums[which] = max(len(list(grp)), maximums[which])

    print "Longest sequence of heads %d, tails %d" % tuple(maximums)

答案 3 :(得分:3)

另一种效率低下的解决方案: - )

import random, re
s = ''.join(str(random.randrange(2)) for c in range(10))
print s
print max(re.findall(r'0+', s))
print max(re.findall(r'1+', s))

>>> 
0011100100
00
111
>>> 

答案 4 :(得分:2)

>>> def toss(count):
        result = []
        for i in range(count):
            result.append("HT"[random.randrange(0, 2)])
        return ''.join(result)

>>> s = toss(200)
>>> h_max = max(len(x) for x in s.split("T"))
>>> t_max = max(len(x) for x in s.split("H"))
>>> print h_max, t_max
4 6

答案 5 :(得分:2)

这不是真正的pythonic,而是折磨,但这是一个简短的版本(带有无意义的1个字符的变量名称,不会少!)

import random
x = ''.join([chr(random.randrange(2)) for i in range(200)])
print max([len(s) for s in x.split(chr(0)) + x.split(chr(1))])

答案 6 :(得分:1)

任何代码都可以更简洁,这可能是一个公理。然而,你的看起来完全是pythonic。

实际上,在反思中也许并没有像这样简洁的公理。如果succinct的意思是“用紧凑的精确表达标记没有浪费的单词”,如果用“单词”来表示代码而不是记忆单词,那么单个单词程序就不能更简洁(除非,或许,它是“退出”计划。)

如果pythonic意味着“具有非凡的规模和力量”,那么除非我们将我们的定义仅限于权力,否则它对于简洁似乎是对立的。我不相信你的程序完全类似于预言的神谕,尽管你可能会把它作为特定预言神谕的ascii肖像来实现。它看起来不像蛇,所以那里也有改进的余地。

import random

def toss(n):
    '''
     ___     ____________
<<<((__O\   (__<>___<>__ \   ____
       \ \_(__<>___<>__)\O\_/O___>-<  hiss
        \O__<>___<>___<>)\___/

    '''
    count = [0,0]
    longest = [0,0]
    for i in xrange(n):
        coinface = random.randrange(2)
        count[coinface] += 1
        count[not coinface] = 0

        if count[coinface] > longest[coinface]:
            longest[coinface] = count[coinface]
        #print coinface, count, longest

    print "longest sequence heads %d, tails %d" %tuple(longest)

if __name__ == '__main__':
    toss(200)

漂亮,是吗?

答案 7 :(得分:1)

import random, itertools

def toss(n):
    faces = (random.randrange(2) for i in range(n))
    longest = [0, 0]
    for face, seq in itertools.groupby(faces):
        longest[face] = max(longest[face], len(list(seq)))
    print "longest sequence heads %d, tails %d" % tuple(longest)

答案 8 :(得分:1)

字符串扫描算法

如果您正在寻找快速算法,那么您可以使用我最近开发的算法来获取面试问题,该问题要求字符串中最长的连续字母串。 See blog entry here

def search_longest_substring(s):
    """
    >>> search_longest_substring('AABBBBCBBBBACCDDDDDDAAABBBBCBBBBACCDDDDDDDAAABBBBCBBBBACCDDDDDDA')
    (7, 'D')
    """
    def find_left(s, midc, mid, left):
        for j in range(mid-1, left-1, -1):
            if s[j] != midc:
                return j + 1
        return left
    def find_right(s, midc, mid, right):
        for k in range(mid+1, right):
            if s[k] != midc:
                return k
        return right
    i, longest = 0, (0, '')
    while i < len(s):
        c = s[i]
        j = find_left(s, c, i, i-longest[0])
        k = find_right(s, c, i, len(s))
        if k-j > longest[0]:
            longest = (k-j, c)
        i = k + longest[0]
    return longest

if __name__ == '__main__':
    import random
    heads_or_tails = "".join(["HT"[random.randrange(0, 2)] for _ in range(20)])
    print search_longest_substring(heads_or_tails)
    print heads_or_tails

该算法在最坏的情况下是O(n)(所有硬币翻转是相同的)或平均情况下的O(n / m)(其中m是最长匹配的长度)。请随意纠正我。

代码不是特别pythonic(即它不使用列表推导或itertools或其他东西)。它是在python中,它是一个很好的算法。

微优化

对于微优化人群,以下是在Windows Vista笔记本电脑上的python 2.6中真正尖叫的变化:

def find_left(s, midc, mid, left):
    j = mid - 1
    while j >= 0:
        if s[j] != midc:
            return j + 1
        j -=  1
    return left
def find_right(s, midc, mid, right):
    k = mid+1
    while k < right:
        if s[k] != midc:
            return k
        k += 1
    return right

使用timeit进行1000次迭代的计时结果:

range: 2.670
xrange: 0.3268
while-loop: 0.255

psyco导入添加到文件中:

try:
    import psyco
    psyco.full()
except ImportError:
    pass
使用psyco和while循环进行1000次迭代时,

0.011。因此,通过明智的微优化和导入psyco,代码运行速度提高了250倍。