У меня есть следующие условия:
Пример: u = [1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, ...]
Программа хочет, чтобы я указал значение члена по заданному индексу.
Я уже нашел способы решить эту проблему с помощью insort, а также составил минимальное дерево двоичного поиска. К сожалению, этот процесс должен быть быстрее, чем у меня, и я не знаю, что делать дальше. Я думал, что BST это сделает, но он недостаточно быстр.
Вот мой код BST:
class BSTNode:
def __init__(self, val=None):
self.left = None
self.right = None
self.val = val
def insert(self, val):
if not self.val:
self.val = val
return
if self.val == val:
return
if val < self.val:
if self.left:
self.left.insert(val)
return
self.left = BSTNode(val)
return
if self.right:
self.right.insert(val)
return
self.right = BSTNode(val)
def inorder(self, vals):
if self.left is not None:
self.left.inorder(vals)
if self.val is not None:
vals.append(self.val)
if self.right is not None:
self.right.inorder(vals)
return vals
и вот моя функция:
from sys import setrecursionlimit
def twotimeslinear(n):
#setrecursionlimit(2000)
i = 0
u = [1]
ended = False
bst = BSTNode()
bst.insert(1)
while i < n and not ended:
for j in range(2, 4):
k = 1
cur = j * bst.inorder([])[i] + 1
bst.insert(cur)
if len(u) == n:
ended = True
break
i+= 1
return bst.inorder([])[n]
Мне просто нужны указания, что я могу сделать, чтобы ускорить этот процесс. Я мог бы решить проблему, если бы только знал, чего мне не хватает. Вероятно, я упускаю из виду какую-то структуру данных, которая работала бы лучше, но я даже не знаю, что искать. Спасибо за любую помощь.
Спасибо; добавление уточнения к вопросу.
Он имеет бесконечную длину. Так вам нужно написать бесконечный генератор или около того?
Добавлю уточнения к вопросу. Программа просто хочет получить значение числа по заданному индексу.
Звучит как работа для кучи или sortedcontainers.SortedList.
Ой, подождите, вам нужно вычислить только один элемент. Генерация всего до этого момента будет слишком медленной, независимо от того, какую структуру данных вы используете.
Насколько большим может быть индекс и сколько времени отводится?
Я считаю, что это вызов, и финальный тест составляет 60 000 элементов.
Ах, черт, я не думал о необходимости математически вычислять N-е, не пересекая его. Я думал, что справлюсь с этим с минимальными вычислениями. Это очень помогает.
Если это всего лишь 60 000, то вычисление каждого элемента должно быть в порядке. Обычно подобные задачи заставляют вас вычислять что-то вроде миллиардного элемента.
Эту последовательность можно найти в Интернет-энциклопедии целочисленных последовательностей: oeis.org/A002977
Проверьте мой отредактированный ответ






Генерация и объединение ys и zs:
from heapq import merge
from itertools import groupby
def twotimeslinear(n):
u = [1]
ys = (2*x+1 for x in u)
zs = (3*x+1 for x in u)
for x, _ in groupby(merge(ys, zs)):
u.append(x)
if n < len(u):
return u[n]
print(*map(twotimeslinear, range(20)))
Занимает ~0,05 секунды для индекса лимита 60 000 и ~0,7 секунды для индекса 1 000 000.
Альтернативная базовая реализация:
def twotimeslinear(n):
u = [1]
i = j = 0
while n >= len(u):
y = 2*u[i] + 1
z = 3*u[j] + 1
m = min(y, z)
u.append(m)
if y == m:
i += 1
if z == m:
j += 1
return u[n]
print(*map(twotimeslinear, range(20)))
И еще вариант, закинув в него тонны батареек :-)
from heapq import merge
from itertools import groupby, tee, chain, islice, repeat
from operator import itemgetter, mul, add
def twotimeslinear(n):
parts = [[1]]
whole = chain.from_iterable(parts)
output, feedback1, feedback2 = tee(whole, 3)
ys = map(1 .__add__, map(2 .__mul__, feedback1))
zs = map(add, map(mul, repeat(3), feedback2), repeat(1)) # different way just for fun
merged = map(itemgetter(0), groupby(merge(ys, zs)))
parts.append(merged)
return next(islice(output, n, None))
print(*map(twotimeslinear, range(20)))
После настройки с помощью кода Python он полностью выполняется в коде C. Это мое глупое хобби.
Спасибо. Это сработало отлично. Мне бы хотелось это понять, но я еще далеко не знаком со стандартной библиотекой Python.
@ ep84 Эх, дело не в библиотеке, а в алгоритме. Я добавил более базовую версию.
@ ep84 Но теперь я пошел в противоположном направлении и добавил версию, использующую нездоровое количество использованных библиотек...
Потрясающая работа. Я не хочу свести к минимуму количество навыков, необходимых для такого алгоритмического мышления. Я могу только надеяться, что мне станет лучше.
вам действительно не следует использовать 1 .__add_ и 2.__mul__ напрямую. используйте operator и functools.partial или выражение lambda
@juanpa.arrivillaga Почему? Все значения являются целыми числами, ваша обычная проблема с типами не применима.
То, что вы описываете, — это не последовательность (даже если вы иногда используете словарь последовательности, например
u(0)=1, а просто набор). Если бы это была последовательность, мы бы знали, в каком порядке их вычислять. И ты не сказал.