优化python代码

时间:2011-01-20 13:25:58

标签: python optimization

有关优化此查找下一个回文

的python代码的任何提示

输入数字可以是1000000位

评论已添加

#! /usr/bin/python
    def inc(lst,lng):#this function first extract the left half of the string then
                     #convert it to int then increment it then reconvert it to string
                     #then reverse  it and finally append it to the left half. 
                     #lst is input number and lng is its length
        if(lng%2==0):

            olst=lst[:lng/2]
            l=int(lng/2)
            olst=int(olst)
            olst+=1
            olst=str(olst)
            p=len(olst)
            if l<p:
                olst2=olst[p-2::-1]
            else:
                olst2=olst[::-1]
            lst=olst+olst2
            return lst
        else:
            olst=lst[:lng/2+1]
            l=int(lng/2+1)
            olst=int(olst)
            olst+=1
            olst=str(olst)
            p=len(olst)
            if l<p:
                olst2=olst[p-3::-1]
            else:
                olst2=olst[p-2::-1]
            lst=olst+olst2
            return lst



    t=raw_input()
    t=int(t)

    while True:
        if t>0:
            t-=1
        else:
            break

        num=raw_input()#this is input number
        lng=len(num)
        lst=num[:]

        if(lng%2==0):#this if find next palindrome to num variable
                     #without incrementing the middle digit and store it in lst.

            olst=lst[:lng/2]
            olst2=olst[::-1]
            lst=olst+olst2

        else:
            olst=lst[:lng/2+1]
            olst2=olst[len(olst)-2::-1]
            lst=olst+olst2

        if int(num)>=int(lst):#chk if lst satisfies criteria for next palindrome
            num=inc(num,lng)#otherwise call inc function
            print num
        else:
            print lst

4 个答案:

答案 0 :(得分:2)

我认为这段代码中的大部分时间都花在将字符串转换为整数和返回。剩下的就是切割字符串并在Python解释器中弹跳。关于这三件事可以做些什么?代码中有一些不必要的转换,我们可以删除。我认为没有办法避免字符串切片。为了最大限度地缩短你在解释器中的时间,你只需编写尽可能少的代码:-)并且它也有助于将所有代码放在函数中。

程序底部的代码需要快速猜测以避免调用inc(),但有一两个错误。以下是我写这部分的方法:

def nextPal(num):
    lng = len(num)
    guess = num[:lng//2] + num[(lng-1)//2::-1]  # works whether lng is even or odd
    if guess > num:  # don't bother converting to int
        return guess
    else:
        return inc(numstr, n)

这个简单的更改使您的代码在不需要调用inc的数字上快100倍,对于需要调用它的数字快3倍。

为了做得更好,我认为你需要完全避免转换为int。这意味着在不使用普通Python整数加法的情况下递增数字的左半部分。您可以使用array并执行添加算法&#34;手动&#34;:

import array

def nextPal(numstr):
    # If we don't need to increment, just reflect the left half and return.
    n = len(numstr)
    h = n//2
    guess = numstr[:n-h] + numstr[h-1::-1]
    if guess > numstr:
        return guess

    # Increment the left half of the number without converting to int.
    a = array.array('b', numstr)
    zero = ord('0')
    ten = ord('9') + 1
    for i in range(n - h - 1, -1, -1):
        d = a[i] + 1
        if d == ten:
            a[i] = zero
        else:
            a[i] = d
            break
    else:
        # The left half was all nines. Carry the 1.
        # Update n and h since the length changed.
        a.insert(0, ord('1'))
        n += 1
        h = n//2

    # Reflect the left half onto the right half.
    a[n-h:] = a[h-1::-1]
    return a.tostring()

对于需要递增的数字,这是另外9倍左右。

通过使用while循环而不是for i in range(n - h - 1, -1, -1),你可以更快地触摸它,并且通过让循环更新数组的两半而不仅仅是更新左边,可以再快两倍 - 用一半然后在最后反映它。

答案 1 :(得分:0)

答案 2 :(得分:0)

你不必找到回文,你可以生成回文。

拆分输入数字并反映它。如果生成的数字太小,则递增左侧并再次反映:

def nextPal(n):
    ns = str(n)
    oddoffset = 0
    if len(ns) % 2 != 0:
        oddoffset = 1

    leftlen = len(ns) / 2 + oddoffset
    lefts = ns[0:leftlen]
    right = lefts[::-1][oddoffset:]
    p = int(lefts + right)
    if p < n:
        ## Need to increment middle digit
        left = int(lefts)
        left += 1
        lefts = str(left)
        right = lefts[::-1][oddoffset:]
        p = int(lefts + right)

    return p

def test(n):
    print n
    p = nextPal(n)
    assert p >= n
    print p

test(1234567890)
test(123456789)
test(999999)
test(999998)
test(888889)
test(8999999)

答案 3 :(得分:0)

使用字符串。 n> = 0


from math import floor, ceil, log10

def next_pal(n): # returns next palindrome, param is an int n10 = str(n) m = len(n10) / 2.0 s, e = int(floor(m - 0.5)), int(ceil(m + 0.5)) start, middle, end = n10[:s], n10[s:e], n10[e:] assert (start, middle[0]) == (end[-1::-1], middle[-1]) #check that n is actually a palindrome r = int(start + middle[0]) + 1 #where the actual increment occurs (i.e. add 1) r10 = str(r) i = 3 - len(middle) if len(r10) > len(start) + 1: i += 1 return int(r10 + r10[-i::-1])

使用日志,更加优化。 n> 9


def next_pal2(n):
    k = log10(n + 1)
    l = ceil(k)
    s, e = int(floor(l/2.0 - 0.5)), int(ceil(l/2.0 + 0.5))
    mmod, emod = 10**(e - s), int(10**(l - e))
    start, end = divmod(n, emod)
    start, middle = divmod(start, mmod)
    r1 = 10*start + middle%10 + 1
    i = middle > 9 and 1 or 2
    j = s - i + 2
    if k == l:
        i += 1
    r2 = int(str(r1)[-i::-1])
    return r1*10**j + r2