Я сравнил решение с perfplot
(мой небольшой проект для таких целей) и обнаружил, что ответ Нолена с наибольшим количеством голосов также самый медленный.
Оба ответа, предоставленные Сковородкиным , намного быстрее. (Обратите внимание на логарифмическую шкалу.)
Чтобы создать сюжет:
import perfplot
import collections
def nolen(number):
answer = set()
answer.add((number, ))
for x in range(1, number):
for y in nolen(number - x):
answer.add(tuple(sorted((x, ) + y)))
return answer
def skovorodkin(n):
return set(skovorodkin_yield(n))
def skovorodkin_yield(n, I=1):
yield (n,)
for i in range(I, n//2 + 1):
for p in skovorodkin_yield(n-i, i):
yield (i,) + p
def accel_asc(n):
return set(accel_asc_yield(n))
def accel_asc_yield(n):
a = [0 for i in range(n + 1)]
k = 1
y = n - 1
while k != 0:
x = a[k - 1] + 1
k -= 1
while 2 * x <= y:
a[k] = x
y -= x
k += 1
l = k + 1
while x <= y:
a[k] = x
a[l] = y
yield tuple(a[:k + 2])
x += 1
y -= 1
a[k] = x + y
y = x + y - 1
yield tuple(a[:k + 1])
def mct(n):
partitions_of = []
partitions_of.append([()])
partitions_of.append([(1,)])
for num in range(2, n+1):
ptitions = set()
for i in range(num):
for partition in partitions_of[i]:
ptitions.add(tuple(sorted((num - i, ) + partition)))
partitions_of.append(list(ptitions))
return partitions_of[n]
perfplot.show(
setup=lambda n: n,
kernels=[
nolen,
mct,
skovorodkin,
accel_asc,
],
n_range=range(1, 17),
logy=True,
# https://stackoverflow.com/a/7829388/353337
equality_check=lambda a, b:
collections.Counter(set(a)) == collections.Counter(set(b)),
xlabel='n'
)
Использовать группы захвата и обратные ссылки.
/^(.{3}).*\1$/
\ 1
относится к тому, что соответствует содержимому первой группы захвата (содержимое ()
) . Регулярные выражения в большинстве языков допускают нечто подобное.
Вам нужны обратные ссылки . Идея состоит в том, чтобы использовать группу захвата для первого бита, а затем возвращаться к ней, когда вы пытаетесь сопоставить последний бит. Вот пример соответствия пары начальных и конечных тегов HTML (из приведенной ранее ссылки):
<([AZ] [A-Z0-9] *) \ b [^>] *>. *? < / \ 1>
Это регулярное выражение содержит только одну пару круглых скобок, в которой записана строка, соответствующая
[AZ] [A-Z0-9] *
, в первой обратной ссылке. Эта обратная ссылка повторно используется с\ 1
(обратная косая черта)./
перед ним - это просто косая черта в закрывающем теге HTML, который мы пытаемся сопоставить.
Применяем это к вашему случаю:
/^(.{3}).*\1$/
(Да, это регулярное выражение, которое опубликовал Брайан Карпер. Просто существует не так много способов сделать это.)
Подробное объяснение для потомков (пожалуйста, не обижайтесь, если оно ниже вас):
^
соответствует началу строки. (. {3})
захватывает три символа любого типа и сохраняет их в группе для последующего использования. . *
соответствует чему-либо как можно дольше. (Тебе все равно, что? s в середине строки.) \ 1
соответствует группе, захваченной на шаге 2. $
соответствует концу строки. Это работает:
my $test = 'abcabc';
print $test =~ m/^([a-z]{3}).*(\1)$/;
Для сопоставления начала и конца вы должны добавить якоря ^
и $
.