Решение задачи о самой длинной возрастающей подпоследовательности: подробное руководство

В мире алгоритмов и решения задач задача о самой длинной возрастающей подпоследовательности (LIS) занимает особое место. Программистам предлагается найти самую длинную подпоследовательность заданной последовательности, которая строго возрастает. В этой статье мы рассмотрим различные методы решения этой проблемы, используя разговорный язык и попутно предоставляя примеры кода.

Метод 1: подход грубой силы
Давайте начнем с самого простого подхода — метода грубой силы. Мы сгенерируем все возможные подпоследовательности и проверим каждую на предмет возрастания порядка. Хотя этот метод неэффективен для больших входных данных, он обеспечивает основу для понимания проблемы.

def longest_increasing_subsequence(nums):
    n = len(nums)
    max_length = 0
    for i in range(n):
        for j in range(i, n):
            subsequence = nums[i:j+1]
            if all(subsequence[k] < subsequence[k+1] for k in range(len(subsequence)-1)):
                max_length = max(max_length, len(subsequence))
    return max_length
# Example usage
sequence = [3, 10, 2, 1, 20]
result = longest_increasing_subsequence(sequence)
print(result)  # Output: 3

Метод 2: динамическое программирование
Подход грубой силы можно оптимизировать с помощью динамического программирования. Мы создадим вспомогательный массив dpдля хранения длины самой длинной возрастающей подпоследовательности, заканчивающейся каждым индексом. Итеративно обновляя dp, мы можем найти самую длинную возрастающую подпоследовательность.

def longest_increasing_subsequence(nums):
    n = len(nums)
    dp = [1] * n
    max_length = 1
    for i in range(1, n):
        for j in range(i):
            if nums[i] > nums[j]:
                dp[i] = max(dp[i], dp[j] + 1)
        max_length = max(max_length, dp[i])
    return max_length
# Example usage
sequence = [3, 10, 2, 1, 20]
result = longest_increasing_subsequence(sequence)
print(result)  # Output: 3

Метод 3: двоичный поиск с помощью массивов
Другой эффективный подход — использовать двоичный поиск вместе с массивами. Мы будем поддерживать массив tailsдля хранения наименьших значений хвоста всех найденных на данный момент возрастающих подпоследовательностей. Обновив tailsстратегически, мы сможем найти самую длинную возрастающую подпоследовательность.

import bisect
def longest_increasing_subsequence(nums):
    tails = [float('inf')] * (len(nums) + 1)
    tails[0] = float('-inf')
    max_length = 0
    for num in nums:
        index = bisect.bisect_left(tails, num)
        tails[index] = num
        max_length = max(max_length, index)
    return max_length
# Example usage
sequence = [3, 10, 2, 1, 20]
result = longest_increasing_subsequence(sequence)
print(result)  # Output: 3

В этой статье мы рассмотрели три различных метода решения проблемы самой длинной возрастающей подпоследовательности. Мы начали с подхода «грубой силы», за которым последовали метод динамического программирования и метод двоичного поиска с использованием массивов. Каждый метод имеет свои преимущества и сложности, что делает их полезными в разных сценариях.