优化Python 3n + 1编程挑战

时间:2016-10-10 19:06:19

标签: python optimization

我正在努力为uvaonlinejudge上的3n + 1问题找到有效的解决方案。我使用的代码使用字典进行记忆。任何人都可以提出一些有助于此代码执行时间的改进吗?目前我的时间限制已超过'提交代码时出错。如果有人有解决问题的方法,请与我分享。请不要将这篇文章标记为DUPLICATE。我已经在stackoverflow上看过this帖子和其他人,但是他们没有回答这里发布的问题。我的代码如下:

import sys

def recCycleLength(n,cycLenDict):
    if n==1:
        return 1
    if n not in cycLenDict:
        if n%2==0:
            cycLen = recCycleLength(n//2, cycLenDict)
            cycLenDict[n] = cycLen + 1
            return cycLen+1
        else:
            cycLen = recCycleLength(3*n+1, cycLenDict)
            cycLenDict[n] = cycLen + 1
            return cycLen+1
    else:
        return cycLenDict[n]


def maxCycle(a, b):
    i = a
    mydict = {} 
    maxLength = 1
    while i <= b:
        m = recCycleLength(i, mydict)
        if m > maxLength:
            maxLength = m
        i = i + 1
    return maxLength


for line in sys.stdin:
    curr_line=line.split()
    num1 = int(curr_line[0])
    num2 = int(curr_line[1])
    if num1>num2:
        num1, num2 = num2, num1
    m = maxCycle(num1, num2)
    print("{} {} {}".format(num1, num2, m))

3 个答案:

答案 0 :(得分:0)

我在您的代码中发现了问题。实际上,您没有保存前一个间隔中为下一个生成的cycLenDict。这就是为什么你的代码如此“慢”的原因,因为它会一遍又一遍地产生所有可能的结局。只需将其移到全球范围内或制作如下:

import sys


def rec(n, cache):
    if n in cache:
        return cache[n]
    if n % 2 == 0:
        cycle = rec(n//2, cache)
    else:
        cycle = rec(3*n+1, cache)
    cache[n] = cycle + 1
    return cache[n]


def cycle(a, b, cache):
    return max(rec(i, cache) for i in range(a, b+1))


if __name__ == '__main__':
    cache = {1: 1}
    for line in sys.stdin:
        a, b = map(int, line.split())
        a, b = min(a, b), max(a, b)
        m = cycle(a, b, cache)
        print("{} {} {}".format(a, b, m))

答案 1 :(得分:0)

代码似乎通过在maxCycle中缓存所有计算结果来最佳地执行mydict

但是,应用程序的输入包含许多要处理的值对,maxCycle将重置mydict = {}并从头开始计算所有值。

我建议全局记住结果。对原始代码的简单修改将是:

cycLenDict = {}   # global dictionary

def recCycleLength(n):   # no cycLenDict argument
    if n==1:
        return 1
    if n not in cycLenDict:
        # ...

def maxCycle(a, b):
    # ...

    while i <= b:
        m = recCycleLength(i)   # no myDict argument

为了让所有内容看起来更好一点(与上面的解决方案相比,性能没有任何差别),请创建一个记住结果的装饰器,以便代码的其余部分不必处理:

def memoize(func):
    """decorate any function which takes positional arguments to cache its results"""

    func.results = {}  # results are stored globally as the funtion's attribute

    def memoized(*a):        # memoized version of func
        if a not in func.results:       # if not cached
            func.results[a] = func(*a)  # save to cache
        return func.results[a]          # return from cache
    return memoized


@memoize       # with this, recCycleLength is called only once for every n value
def recCycleLength(n):
    if n==1:
        return 1
    elif n%2==0:
        return recCycleLength(n//2) + 1
    else:
        return recCycleLength(3*n+1) + 1


def maxCycle(a, b):
    return max(recCycleLength(i) for i in range(a, b+1))

答案 2 :(得分:0)

linear <- function(x, a, b) a + b*x