#python #python-3.x #algorithm #sequence
#python #python-3.x #алгоритм #последовательность
Вопрос:
Предположим, у вас есть следующий список
a_list = [1, 2, 3, 4, 8, 7, 6]
Мы хотим найти наименьшее ‘число’ возрастающих последовательностей, содержащих все элементы списка с обеих сторон списка.
Для приведенного выше примера мы получим
последовательность = [[1,2,3,4,8], [6,7]]
Что дает ответ 2. Это потому, что мы можем сформировать возрастающую последовательность слева направо как [1,2,3,4,8] . Мы также можем сформировать возрастающую последовательность справа налево как [6,7] .
Я рассмотрел возможность создания двух списков, которые дают все возрастающие последовательности списка и обратные списку, как таковые
left_to_right = [[1,2,3,4,8],[7], [6]]
right_to_left = [[6,7,8], [4], [3], [2], [1]]
но я не уверен, куда идти дальше. Есть мысли?
Комментарии:
1. Я не понимаю вопроса. Разве ответ не всегда равен 2? Можете ли вы привести пример списка, для которого ответ не равен 2?
2. @Stef [1, 10, 2, 9, 3, 8] например
3. @Neil Каким будет ответ в этом случае? Существует возрастающая последовательность [1, 10] в начале и [8] в конце.
4. @Stef Я ничего не вижу в вопросе OPs о начале и конце, только «слева» и «справа». Итак, мой ответ будет 3: [[1,10],[2,9], [3,8]]
5. Пример OP также поддерживает эту интерпретацию
Ответ №1:
РЕДАКТИРОВАТЬ: приведенный ниже оригинал излишне сложен. Увеличение «слева» просто означает уменьшение. Поэтому просто выполните итерацию по списку один раз, отслеживая возрастающие и убывающие последовательности с помощью логического флага, делая их как можно длиннее, а затем посчитайте в конце. Это должно сработать. Не проверено.
increasing = None
current_item = _list[0]
all_sequences = []
current_sequence = [_list[0]]
for item in _list[1:]:
if increasing is None:
increasing = item > current_sequence[-1]
current_sequence.append(item)
elif (item > current_item and increasing) or (item < current_item and not increasing):
current_sequence.append(item)
elif (item > current_item and not increasing) or (item < current_item and increasing):
all_sequences.append(current_sequence)
current_sequence = [item]
increasing = None
current_item = item
all_sequences.append(current_sequence)
result = len(all_sequences)
Оригинальный ответ:
Вот несколько мыслей
Во-первых, я предполагаю, что ваша функция всегда будет делать последовательности как можно длиннее. Итак, вы получаете это:
left_to_right = [[1,2,3,4,8],[7], [6]]
А не, например, это:
left_to_right = [[1,2],[3],[4,8],[7], [6]]
(который технически также является списком возрастающих последовательностей).
Ваша следующая задача — убедиться, что вы получили все числа в списке. Итак, вы должны выбрать несколько возрастающих последовательностей. Чем длиннее выбранная вами последовательность, тем больше чисел вы получаете для «использования», не добавляя слишком много последовательностей. Чтобы взять ваш пример:
left_to_right = [[1,2,3,4,8],[7], [6]]
right_to_left = [[6,7,8], [4], [3], [2], [1]]
Соедините два списка вместе:
all = left_to_right right_to_left
Теперь найдите самую длинную последовательность:
longest = max(all, key=lambda x:len(x))
Это даст вам
[1,2,3,4,8]
Теперь повторите, захватывая следующую самую длинную последовательность, продолжайте, пока не захватите все числа в списке. Это дало бы вам:
[[1,2,3,4,8], [6,7,8]]
В качестве последнего шага проверьте наличие дубликатов. Тогда вы получите
[[1,2,3,4,8], [6,7]]
по желанию
Я подозреваю, что это всегда должно давать вам наименьшее количество последовательностей. Но, возможно, если есть дубликаты, я могу ошибаться.
Комментарии:
1. Выглядит хорошо, вы могли бы дополнительно оптимизировать, не создавая списки, а только считая их.
2. Большое вам спасибо! Конечно, его уменьшение и способ его решения — сформировать максимальные «скользящие» возрастающие или убывающие последовательности. Единственное, что я хотел бы добавить, это то, что уравнение может быть неубывающим, а не увеличиваться, и не увеличиваться, а не уменьшаться, чтобы учесть смежные повторяющиеся значения.