В информатике задача максимальной суммы подмассива , также известная как задача максимальной суммы сегмента , — это задача нахождения непрерывного подмассива с наибольшей суммой в заданном одномерном массиве A[1...n] чисел. Она может быть решена во времени и пространстве.
Формально задача состоит в том, чтобы найти индексы и при , такие, чтобы сумма
максимально возможное значение. (Некоторые формулировки задачи также позволяют рассматривать пустой подмассив; по соглашению сумма всех значений пустого подмассива равна нулю.) Каждое число во входном массиве A может быть положительным, отрицательным или нулевым. [1]
Например, для массива значений [−2, 1, −3, 4, −1, 2, 1, −5, 4] непрерывный подмассив с наибольшей суммой — это [4, −1, 2, 1] с суммой 6.
Некоторые свойства этой проблемы:
Хотя эту задачу можно решить с помощью нескольких различных алгоритмических методов, включая метод грубой силы, [2] «разделяй и властвуй», [3] динамическое программирование [4] и сведение к кратчайшим путям, простой однопроходный алгоритм, известный как алгоритм Кадане, решает ее эффективно.
Задача максимального подмассива была предложена Ульфом Гренадером в 1977 году как упрощенная модель для оценки максимального правдоподобия шаблонов в оцифрованных изображениях. [5]
Гренандер хотел найти прямоугольный подмассив с максимальной суммой в двумерном массиве действительных чисел. Алгоритм грубой силы для двумерной задачи выполняется за время O ( n 6 ); поскольку это было непозволительно медленно, Гренандер предложил одномерную задачу, чтобы получить представление о ее структуре. Гренандер вывел алгоритм, который решает одномерную задачу за время O ( n 2 ), [примечание 1] улучшая время выполнения грубой силы O ( n 3 ). Когда Майкл Шамос услышал о задаче, он за одну ночь разработал для нее алгоритм «разделяй и властвуй» за O ( n log n ) . Вскоре после этого Шамос описал одномерную задачу и ее историю на семинаре в Университете Карнеги-Меллона, на котором присутствовал Джей Кадане , который за минуту разработал алгоритм с временем O ( n ) [5] [6] [7] , который является максимально быстрым. [примечание 2] В 1982 году Дэвид Грайс получил тот же алгоритм с временем O ( n ) применив «стандартную стратегию» Дейкстры ; [8] в 1989 году Ричард Берд вывел его путем чисто алгебраической манипуляции алгоритмом грубой силы, используя формализм Берда–Меертенса . [9]
Двумерное обобщение Гренадера может быть решено за время O( n 3 ) либо с помощью алгоритма Кадане в качестве подпрограммы, либо с помощью подхода «разделяй и властвуй». Немного более быстрые алгоритмы, основанные на умножении матриц расстояний, были предложены Тамаки и Токуямой (1998) и Такаокой (2002). Есть некоторые свидетельства того, что не существует значительно более быстрого алгоритма; алгоритм, который решает двумерную задачу максимального подмассива за время O( n 3−ε ) для любого ε>0, будет подразумевать аналогичный быстрый алгоритм для задачи кратчайших путей для всех пар . [10]
Задачи максимального подмассива возникают во многих областях, таких как анализ геномной последовательности и компьютерное зрение .
Анализ геномной последовательности использует алгоритмы максимального подмассива для идентификации важных биологических сегментов белковых последовательностей, которые имеют необычные свойства, путем присвоения баллов точкам внутри последовательности, которые являются положительными, когда присутствует мотив, который нужно распознать, и отрицательными, когда его нет, а затем поиска максимального подмассива среди этих баллов. Эти проблемы включают консервативные сегменты, богатые GC регионы, тандемные повторы, фильтр низкой сложности, домены связывания ДНК и регионы с высоким зарядом. [11]
В компьютерном зрении растровые изображения обычно состоят только из положительных значений, для которых задача максимального подмассива тривиальна: результатом всегда является весь массив. Однако после вычитания порогового значения (например, среднего значения пикселя) из каждого пикселя, так что пиксели выше среднего будут положительными, а пиксели ниже среднего будут отрицательными, задача максимального подмассива может быть применена к измененному изображению для обнаружения ярких областей внутри него. [12]
Алгоритм Кадане сканирует заданный массив слева направо. На шаге th он вычисляет подмассив с наибольшей суммой, заканчивающейся на ; эта сумма сохраняется в переменной . [примечание 3]
Более того, он вычисляет подмассив с наибольшей суммой в любом месте в , сохраняется в переменной , [примечание 4]
и легко получается как максимум из всех значений , которые были видны до сих пор, см. строку 7 алгоритма.current_sum
best_sum
current_sum
Как инвариант цикла , на шаге th старое значение содержит максимум по всей сумме . Следовательно, [примечание 5]
является максимумом по всей сумме . Чтобы расширить последний максимум, чтобы охватить также случай , достаточно рассмотреть также подмассив singleton . Это делается в строке 6 путем назначения в качестве нового значения , которое после этого содержит максимум по всей сумме .current_sum
current_sum
current_sum
current_sum
Таким образом, проблему можно решить с помощью следующего кода [13] , написанного на языке Python .
def max_subarray ( числа ): """Найдите наибольшую сумму любого смежного подмассива.""" best_sum = float ( '-inf' ) текущая_сумма = 0 для x в числах : текущая_сумма = макс ( х , текущая_сумма + х ) лучшая_сумма = макс ( лучшая_сумма , текущая_сумма ) вернуть лучшую_сумму
Если входные данные не содержат положительных элементов, возвращаемое значение равно наибольшему элементу (т. е. значению, ближайшему к 0), или отрицательной бесконечности, если входные данные были пустыми. Для корректности следует вызывать исключение, когда входной массив пуст, поскольку пустой массив не имеет максимального непустого подмассива. Если массив непустой, его первый элемент можно использовать вместо отрицательной бесконечности, если необходимо избежать смешивания числовых и нечисловых значений.
Алгоритм можно адаптировать к случаю, допускающему пустые подмассивы, или для отслеживания начальных и конечных индексов максимального подмассива.
Этот алгоритм вычисляет максимальный подмассив, заканчивающийся в каждой позиции, из максимального подмассива, заканчивающегося в предыдущей позиции, поэтому его можно рассматривать как случай динамического программирования .
Пример запуска |
---|
Оригинальный алгоритм Кадане решает вариант проблемы, когда допускаются пустые подмассивы. [4] [7]
Этот вариант вернет 0, если входные данные не содержат положительных элементов (включая случаи, когда входные данные пусты). Он получается двумя изменениями в коде: в строке 3 best_sum
следует инициализировать значением 0 для учета пустого подмассива
лучшая_сумма = 0 ;
и строка 6 в цикле for current_sum
должна быть обновлена как max(0, current_sum + x)
. [примечание 6]
текущая_сумма = макс ( 0 , текущая_сумма + x )
Как инвариант цикла , на шаге th старое значение содержит максимум по всей сумме . [примечание 7]
Следовательно,
является максимумом по всей сумме . Чтобы расширить последний максимум, чтобы охватить также случай , достаточно рассмотреть также пустой подмассив . Это делается в строке 6 путем назначения в качестве нового значения , которое после этого содержит максимум по всей сумме . Проверенные машиной коды C / Frama-C обоих вариантов можно найти здесь.current_sum
current_sum
current_sum
current_sum
Алгоритм можно модифицировать, чтобы отслеживать также начальные и конечные индексы максимального подмассива.
Благодаря способу, которым этот алгоритм использует оптимальные подструктуры (максимальный подмассив, заканчивающийся в каждой позиции, вычисляется простым способом из связанной, но меньшей и перекрывающейся подзадачи: максимальный подмассив, заканчивающийся в предыдущей позиции), этот алгоритм можно рассматривать как простой/тривиальный пример динамического программирования .
Сложность выполнения алгоритма Кадане составляет , а его пространственная сложность составляет . [4] [7]
Аналогичные проблемы могут быть поставлены для массивов более высокой размерности, но их решения более сложны; см., например, Takaoka (2002). Brodal & Jørgensen (2007) показали, как найти k наибольших сумм подмассивов в одномерном массиве за оптимальное время .
Максимальная сумма k -непересекающихся подмассивов также может быть вычислена за оптимальное время . [14]
MaxEndingHere
в Bentley (1989) и c
в Gries (1982)MaxSoFar
в Bentley (1989) и s
в Gries (1982)x
x
вместо 0
в приведенной выше версии без пустых подмассивов позволяет сохранить инвариантность цикла в начале th-го шага.current_sum