如何生成给定范围内的回文数列表?

时间:2013-05-02 17:35:38

标签: python python-2.7

假设范围是: 1 X 120

这就是我的尝试:

>>> def isPalindrome(s):
    ''' check if a number is a Palindrome '''
    s = str(s)
    return s == s[::-1]

>>> def generate_palindrome(minx,maxx):
    ''' return a list of Palindrome number in a given range '''
    tmpList = []
    for i in range(minx,maxx+1):
        if isPalindrome(i):
            tmpList.append(i)

    return tmpList

>>> generate_palindrome(1,120)

[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111]

但是,这是O(n)

如何改进此算法以使其更快?

PS。这是Python 2.7

6 个答案:

答案 0 :(得分:5)

您的方法可能是:

palindromes = [x for x in xrange(min, max) if isPalindrome(x)]

你能做到这一点并且采用非线性算法的唯一方法是自己生成回文,而不是测试。

可以通过采用先前的回文并在左侧和右侧添加相同的数字来生成回文,因此这是一个起点。

假设您从1开始:

通过将每个数字从1:9添加到左侧和右侧来获得可能的回文:

111
212
313
...

而且,你必须生成几个条目,其中每个数字在范围内相等......

答案 1 :(得分:2)

我发现这是一个有趣的任务,所以我给了我生锈的蟒蛇技能一些练习。

def generate_palindromes_with_length(l):
''' generate a list of palindrome numbers with len(str(palindrome)) == l '''
    if l < 1:
        return []
    if l == 1:
        return [x for x in range(10)]
    p = []
    if (l % 2):
        half_length = (l - 1) / 2
        for x in xrange(0, 10):
            for y in xrange(10 ** (half_length - 1), 10 ** half_length):
                p.append(int(str(y) + str(x) + str(y)[::-1]))
    else:
        half_length = l / 2
        for x in xrange(10 ** (half_length - 1), 10 ** half_length):
            p.append(int(str(x) + str(x)[::-1]))
    p.sort()
    return p


def generate_palindrome(minx, maxx):
''' return a list of palindrome numbers in a given range '''
    min_len = len(str(minx))
    max_len = len(str(maxx))
    p = []
    for l in xrange(min_len, max_len + 1):
        for x in generate_palindromes_with_length(l):
            if x <= maxx and x >= minx:
                p.append(x)
    p.sort
    return p

generate_palindromes_with_length是此处的关键部分。该函数生成带有给定小数位数的回文。它对奇数和偶数小数位使用不同的策略。示例:如果请求长度为5,则会生成带有abxba模式的回文,其中abx是1到9之间的任意数字(加{{ 1}}可能是0)。如果4是请求的长度,则模式为x

abba只需收集所需长度的回文',  并照顾边界。

算法在O(2 * p)中,p是回文数。

该算法确实有效。然而,由于我的python技能已经生疏,所以对于更优雅的解决方案的任何建议都表示赞赏。

答案 2 :(得分:1)

这是一个有趣的运动!这是我对回文数字生成器的看法,O(n ^(1/2)):

def palindrome_number_generator():
    yield 0    
    lower = 1
    while True:
        higher = lower*10
        for i in xrange(lower, higher):    
            s = str(i)
            yield int(s+s[-2::-1])
        for i in xrange(lower, higher):    
            s = str(i)
            yield int(s+s[::-1])
        lower = higher


def palindromes(lower, upper):
    all_palindrome_numbers = palindrome_number_generator()
    for p in all_palindrome_numbers:
        if p >= lower:
            break
    palindrome_list = [p]
    for p in all_palindrome_numbers:
        # Because we use the same generator object,
        # p continues where the previous loop halted.
        if p >= upper:
            break
        palindrome_list.append(p)
    return palindrome_list


print palindromes(1, 120)

因为它是数字,所以生成器必须单独处理0:它应该包括0而不是010。

答案 3 :(得分:1)

如果你想让它立即给你一个清单,这将有效:

def palindrome_range(start,stop,step=1):
    ret=[x for x in xrange(start,step,stop) if str(x)==str(x)[::-1]]
    return ret

但是,如果你想要一个发电机,你可以使用:

def palindrome_range(start,stop,step=1):
    for x in xrange(start,stop,step):
        if str(x)==str(x)[::-1]:
            yield x

这些将帮助您加快速度,具体取决于您使用它的内容。例如,如果您想要遍历回文,那么生成器将为您提供良好的服务。但是,如果您需要整个列表,则返回的常规列表会更好。但值得注意的是,xrange在这种情况下比范围要好得多,因为它更好地处理大型列表,如文档here所述。

答案 4 :(得分:1)

受Quant Metropolis答案的启发,这是我对在不同碱基(从2到10)中生成回文序列的看法。

首先,我们定义一个辅助生成器,该生成器为我们提供所需长度的某些基数的所有数字:

def nums_in_base(ndigits=3, b=10, _toplevel=True):
    """
    generate all nubmers in the given base of the given length
    `_toplevel` controls whether to add 0 at the beginning in the process of recursive calls
    """
    if ndigits == 0:
        yield ''
    else:
        for num in nums_in_base(ndigits-1, b, False):
            for i in range(int(_toplevel), b):
                yield str(i) + num

请注意,它返回字符串。

现在我们写回文生成器本身:

def any_base_digit_palindromes(n_max_half_digits, b=10):
    """
    generate all palindromes in the given base and
    less than the given length
    palindromes consist of two parts, `n_max_half_digits` controls
    the maximum length of those halves 
    i.e., real max length of a palindrome is double the `n_max_half_digits`
    """
    if n_max_half_digits > 1:
        yield from digit_palindromes(n_max_half_digits - 1, b)

    for num in nums_in_base(n_max_half_digits, b):
        yield num + num[-2::-1]
        yield num + num[::-1]

不确定big-O,但是对于基数10中小于1,000,000的所有回文,与OP版本的经验比较很简单,OP版本约为400ms,我的版本约为0.7ms。

P.S。可以将其扩展到大于10的基数,但这将需要使用显式的预定义数字数组而不是两个生成器中的范围。

答案 5 :(得分:0)

正如@ it-ninja写的只是改变步骤并停止

def palindrome_range(start,stop,step=1):
    ret=[x for x in xrange(start,stop,step) if str(x)==str(x)[::-1]]
    return ret

这将给出给定范围内的所有回文

相关问题