【问题标题】:I am trying to find the nth binary palindrome我试图找到第 n 个二进制回文
【发布时间】:2017-02-02 04:16:49
【问题描述】:

Binary palindromes: numbers whose binary expansion is palindromic.
二进制回文 -> 是一个二进制表示为回文的数字。
Here is link to the solution with naive approach

我已经阅读了上面的链接,它给出了一个找到第 n 个二进制回文的公式。我无法理解并因此编写解决方案。

def palgenbase2(): # generator of palindromes in base 2
    #yield 0
    x, n, n2 = 1, 1, 2
    m = 1;
    while True:
        for y in range(n, n2):
            s = format(y, 'b')
            yield int(s+s[-2::-1], 2)
        for y in range(n, n2):
            s = format(y, 'b')
            yield int(s+s[::-1], 2)
        x += 1
        n *= 2
        n2 *= 2
        if n2 > 1000000000:
            break

ans = {}

for i,j in  enumerate(palgenbase2()):
    print i,j
    ans[i]=j

with open("output","a") as f:
    f.write(ans)

#use the saved output to give answer to query later
#this will work but it takes too much time.

n = int(raw_input())
for c in range(0,n):
    z = int(raw_input())
    print ans[z]

这是一个 Python 代码,但它会生成所有此类回文。
我需要程序帮助才能直接获取第 n 个二进制回文。
如下:

输入 -> 1 函数 -> f(n)
输出 -> 第 n 个二进制回文。

我们可以使用here 提到的公式更及时地做到这一点吗?

【问题讨论】:

  • 请附上您尝试的解决方案,以及为什么它们不起作用。有关详细信息,请参阅 Stack Overflow 问题清单。
  • 投反对票的原因如下:您的问题没有显示任何尝试自己解决问题和/或理解代码的痕迹。您只是提供了一些复制/粘贴的代码,并希望有人为您完成其余的工作。如果您能在提供的代码中准确指出您不理解的内容,我将很乐意提供帮助。
  • 抱歉,我没有尝试分析该公式的工作原理。但我只是测试了它,它产生的结果与生成器相同。而且您还没有解释是什么阻止您在 Python 中实现该递归公式。但我想如果我发布我的实现,你可能会得到一些想法。 :)
  • @dsgdfg:当然,这可以让您测试number 是否是二进制回文。但是 lordzuko 想要一个函数,例如 bin_palindrome(n),它返回第 n 个二进制回文而不对所有以前的二进制回文进行暴力搜索。
  • 当然,OEIS _可能有点神秘。例如,我不了解 Maple,因此 Maple 代码对我来说毫无用处。 :) 但是,伪代码还不错,恕我直言。您只需要从Recursion for n>2: a(n)=2^(2k-q)+1+2^p*a(m) 开始的部分。但无论如何,希望我的回答能让它更清楚一点。

标签: python algorithm binary palindrome


【解决方案1】:

这是A006995 给出的递归算法的一个相当简单的实现。

为了提高效率,我使用位移来执行二进制求幂:当x 是非负整数时,1 << x 等效于2 ** x,但速度要快得多(至少,它在 Python 2和标准 CPython 上的 Python 3)。

此外,为了使递归更有效,该函数将先前计算的值存储在字典中。这也让我们可以轻松处理 n <= 2 时,递归公式本身无法处理。

#!/usr/bin/env python

''' Binary palindromes

    Find (non-negative) integers which are palindromes when written in binary

    See http://stackoverflow.com/q/39675412/4014959
    and https://oeis.org/A006995

    Written by PM 2Ring 2016.09.24

    Recursion for n>2: a(n)=2^(2k-q)+1+2^p*a(m), where k:=floor(log_2(n-1)), and p, q and m are determined as follows:

    Case 1: If n=2^(k+1), then p=0, q=0, m=1;

    Case 2: If 2^k<n<2^k+2^(k-1), then set i:=n-2^k, p=k-floor(log_2(i))-1, q=2, m=2^floor(log_2(i))+i;

    Case 3: If n=2^k+2^(k-1), then p=0, q=1, m=1;

    Case 4: If 2^k+2^(k-1)<n<2^(k+1), then set j:=n-2^k-2^(k-1), p=k-floor(log_2(j))-1, q=1, m=2*2^floor(log_2(j))+j; 
'''

#Fast Python 3 version of floor(log2(n))
def flog2(n):
    return n.bit_length() - 1

def binpal(n, cache={1:0, 2:1, 3:3}):
    if n in cache:
        return cache[n]

    k = flog2(n - 1)
    b = 1 << k
    a, c = b >> 1, b << 1

    if n == c:
        p, q, m = 0, 0, 1
    elif b < n < a + b:
        i = n - b
        logi = flog2(i)
        p, q, m = k - logi - 1, 2, (1 << logi) + i
    elif n == a + b:
        p, q, m = 0, 1, 1
    else:
        #a + b < n < c
        i = n - a - b
        logi = flog2(i)
        p, q, m = k - logi - 1, 1, (2 << logi) + i

    result = (1 << (2*k - q)) + 1 + (1 << p) * binpal(m)
    cache[n] = result
    return result

def palgenbase2(): 
    ''' generator of binary palindromes '''
    yield 0
    x, n, n2 = 1, 1, 2
    while True:
        for y in range(n, n2):
            s = format(y, 'b')
            yield int(s+s[-2::-1], 2)
        for y in range(n, n2):
            s = format(y, 'b')
            yield int(s+s[::-1], 2)
        x += 1
        n *= 2
        n2 *= 2

gen = palgenbase2()

for i in range(1, 30):
    b = next(gen)
    c = binpal(i)
    print('{0:>2}: {1} {1:b} {2}'.format(i, b, c))

输出

 1: 0 0 0
 2: 1 1 1
 3: 3 11 3
 4: 5 101 5
 5: 7 111 7
 6: 9 1001 9
 7: 15 1111 15
 8: 17 10001 17
 9: 21 10101 21
10: 27 11011 27
11: 31 11111 31
12: 33 100001 33
13: 45 101101 45
14: 51 110011 51
15: 63 111111 63
16: 65 1000001 65
17: 73 1001001 73
18: 85 1010101 85
19: 93 1011101 93
20: 99 1100011 99
21: 107 1101011 107
22: 119 1110111 119
23: 127 1111111 127
24: 129 10000001 129
25: 153 10011001 153
26: 165 10100101 165
27: 189 10111101 189
28: 195 11000011 195
29: 219 11011011 219

如果您需要在 Python 2 上运行它,您将无法使用 flog2 函数,因为 Python 2 整数没有 bit_length 方法。这是一个替代版本:

from math import floor, log

def flog2(n):
    return int(floor(log(n) / log(2)))

【讨论】:

    【解决方案2】:

    我不会写完整的代码。 让我们检查一下算法

    这些列是:位计数、组合、组合计数

    • 1 1 | 1
    • 2 11 | 1
    • 3 101 111 | 2
    • 4 1001 1111 | 2
    • 5 10001 10101 11011 11111 |4
    • 6 100001 101101 110011 11111 |4

    如果您遵循这个系列,您将每两步成倍增加。设 n 为位数,其中位数具有以下组合数量: 2>1) 。 现在我不知道是否可以以接近的形式计算它,但递归非常快,因为它是指数的: 设 n 为直到 n-1 位的计数,m 为当前计数

    int i,n=0,m=0;
    for (i=1;m<nth;i++)
    {
       n=m;
       m+=2<<((i-1)>>1);
    }
    

    现在你知道需要多少位了:i

    您构建一个 char 数组,其中 (i+1)/2 位为 100...0 您以二进制形式添加 (nth-n)-1 (-1 因为基于 0)。还有奥普拉!你镜像你的令牌并结束。 示例:您需要 12 个元素 您将求和 1+1+2+2+4+4 。所以你知道你的第 12 个元素有 6 位。 直到 5 位你有 10 个元素。所以 12-10=2 2-1=1 你有点像 100(6位/2) 你添加 1-> 二进制 1 100+1=101 您的第 n 个回文数具有以下形式 101101。它也适用于奇数位数。检查奇点 1 和 2 位计数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-07
      • 2017-02-19
      • 2011-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-27
      相关资源
      最近更新 更多