Я пытаюсь найти n-й двоичный палиндром

Двоичные палиндромы: числа, двоичное представление которых является палиндромным.
Двоичный палиндром -> это число, двоичное представление которого представляет собой палиндром.
Вот ссылка на решение с наивным подходом

Я прочитал ссылку выше, и она дает формулу для поиска 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 ‹= n ‹= 1000000000
Функция -> f(n)
вывод -> n-й двоичный палиндром.

Можем ли мы сделать это быстрее, используя формулу, упомянутую здесь?


person lordzuko    schedule 24.09.2016    source источник
comment
Пожалуйста, укажите свои попытки решения и почему они не сработали. Дополнительные сведения см. в контрольном списке вопросов о переполнении стека.   -  person jadsq    schedule 24.09.2016
comment
@jadsq Кажется, я упомянул, что не могу кодировать, потому что не могу понять, что они там говорят. Более того, я перепробовал почти все ссылки здесь на stackoverflow, и ни одна из них не работает для меня.   -  person lordzuko    schedule 24.09.2016
comment
Я пробовал в java с некоторым наивным подходом, но этого недостаточно, если вам нужно, я могу дать это решение.   -  person lordzuko    schedule 24.09.2016
comment
Вы вообще хоть что-нибудь понимаете в питоне?   -  person jadsq    schedule 24.09.2016
comment
@jadsq Есть какая-то конкретная причина для отрицательного голоса?   -  person lordzuko    schedule 24.09.2016
comment
@jadsq да, я понимаю   -  person lordzuko    schedule 24.09.2016
comment
Понижение по следующей причине: ваш вопрос не показывает никаких следов попыток решить проблему самостоятельно и/или понять код. Вы только что предоставили код копирования/вставки и ожидаете, что кто-то сделает остальную работу за вас. Я был бы рад помочь, если бы вы могли точно определить, что именно вы не понимаете в предоставленном коде.   -  person jadsq    schedule 24.09.2016
comment
@jadsq В любом случае я предоставил ссылку на Oeis Это ссылка на мое решение. Я пытался.   -  person lordzuko    schedule 24.09.2016
comment
Вы должны поместить код своего решения в сам вопрос, а не в качестве ссылки на внешний сайт. Однако этот код в вашей ссылке ideone — это Java, а не Python, и он просто выполняет поиск палиндромов грубой силой, и он гораздо менее эффективен, чем код генератора из OEIS, который вы опубликовали.   -  person PM 2Ring    schedule 24.09.2016
comment
Псевдокод рекурсивной формулы в OEIS немного многословен, но реализовать его на Python не так уж и сложно. Если вы не можете понять это, вам нужно сделать то, что предложил jadsq: точно указать, что вы не понимаете в предоставленном псевдокоде.   -  person PM 2Ring    schedule 24.09.2016
comment
@ PM2Ring Спасибо за ваше руководство. Недавно я стал активным в stackoverflow, поэтому я не понимаю всех требований платформы. Я понимаю, что подход является грубой силой, и поэтому я пытаюсь найти лучший подход. код, который они предоставили, я пытался понять, почему он работает? Если возможно, не могли бы вы дать мне некоторые идеи?   -  person lordzuko    schedule 24.09.2016
comment
@PM2Ring Я хочу реализовать эту рекурсивную формулу в Python. Я не могу этого сделать.   -  person lordzuko    schedule 24.09.2016
comment
s = True, если bin(number)[2:] == bin(number)[2:][::-1] else False Выведите s для результата   -  person dsgdfg    schedule 24.09.2016
comment
Но точка @PM2Ring важна. Так что сосредоточьтесь на обучении, а не на чем-то.   -  person dsgdfg    schedule 24.09.2016
comment
Извините, я не пытался анализировать, как работает эта формула. Но я только что проверил его, и он дает те же результаты, что и генератор. И вы до сих пор не объяснили, что мешает вам реализовать эту рекурсивную формулу в Python. Но я думаю, если я опубликую свою реализацию, вы можете получить несколько идей. :)   -  person PM 2Ring    schedule 24.09.2016
comment
@dsgdfg: Конечно, это позволяет вам проверить, является ли number бинарным палиндромом. Но lordzuko нужна функция, например, bin_palindrome(n), которая возвращает n-й бинарный палиндром, не выполняя перебор всех предыдущих бинарных палиндромов.   -  person PM 2Ring    schedule 24.09.2016
comment
@ PM2Ring Единственное, что мне мешает, - это загадочный способ написания этих формул на веб-сайте OEIS. На самом деле меня смущает тот оператор, который они пытаются использовать, где (особенно мощность, зор и деление). Ваша реализация будет очень полезна. И даст ответ на этот вопрос и другим.   -  person lordzuko    schedule 24.09.2016
comment
Конечно, OEIS может быть немного загадочной. Например, я не знаю Maple, поэтому код Maple для меня бесполезен. :) Впрочем, псевдокод не так уж и плох, ИМХО. Вам просто нужен раздел, начинающийся с Recursion for n>2: a(n)=2^(2k-q)+1+2^p*a(m). Но в любом случае, надеюсь, мой ответ сделает это немного яснее.   -  person PM 2Ring    schedule 24.09.2016
comment
стройте их, а не проверяйте, является ли число палиндромом!   -  person jurhas    schedule 24.09.2016
comment
@jurhas: Это не очень эффективно, если хотите, скажем, binpal(1000000000), но опубликованный мной код может сделать это менее чем за 0,12 секунды на моей старой машине с частотой 2 ГГц.   -  person PM 2Ring    schedule 24.09.2016
comment
@jurhas Какой подход вы используете для построения N-го двоичного палиндрома. Пожалуйста, напишите ответ, это определенно поможет многим людям.   -  person lordzuko    schedule 24.09.2016


Ответы (2)


Вот довольно простая реализация рекурсивного алгоритма, приведенная по адресу A006995.

Чтобы сделать его более эффективным, я использую битовый сдвиг для выполнения двоичного возведения в степень: когда x является неотрицательным целым числом, 1 << x эквивалентно 2 ** x, но значительно быстрее (по крайней мере, это происходит как в Python 2, так и в Python 3 на стандартном CPython).

Кроме того, чтобы сделать рекурсию более эффективной, функция сохраняет ранее вычисленные значения в словаре. Это также позволяет нам легко обрабатывать, когда 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)))
person PM 2Ring    schedule 24.09.2016

Я не буду писать полный код. Проверим алгоритм

Эти столбцы: количество битов, комбинации, количество комбинаций

  • 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‹‹((n-1)››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

Вы строите массив символов с (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 бит

person jurhas    schedule 25.09.2016