Недавно я беседовал с компанией, и они попросили меня написать алгоритм, который найдет подпоследовательность с наибольшей суммой элементов в массиве. Элементы массива могут быть отрицательными. Для этого существует O (n) решение? Любые хорошие решения очень ценятся.
Найти подпоследовательность с наибольшей суммой элементов в массиве
Ответ 1
Если вам нужна самая большая сумма последовательных чисел, тогда может получиться что-то вроде этого:
$cur = $max = 0;
foreach ($seq as $n)
{
$cur += $n;
if ($cur < 0) $cur = 0;
if ($cur > $max) $max = $cur;
}
Это как раз у меня на голове, но кажется правильным. (Игнорируя, что он принимает 0, является ответом для пустых и всех отрицательных множеств.)
Edit:
Если вам также нужна позиция последовательности:
$cur = $max = 0;
$cur_i = $max_i = 0;
$max_j = 1;
foreach ($seq as $i => $n)
{
$cur += $n;
if ($cur > $max)
{
$max = $cur;
if ($cur_i != $max_i)
{
$max_i = $cur_i;
$max_j = $max_i + 1;
}
else
{
$max_j = $i + 1;
}
}
if ($cur < 0)
{
$cur = 0;
$cur_i = $i + 1;
}
}
var_dump(array_slice($seq, $max_i, $max_j - $max_i), $max);
Там может быть более сжатый способ сделать это. Опять же, он имеет те же предположения (по крайней мере одно положительное целое число). Кроме того, он находит первую большую последовательность.
Изменить: изменил его, чтобы использовать max_j
(эксклюзивный) вместо max_len
.
Ответ 2
Если вы имеете в виду самую длинную возрастающую подпоследовательность, см. ответ codaddict.
Если, с другой стороны, вы имеете в виду поиск вспомогательного массива с максимальной суммой (имеет смысл только с отрицательными значениями), тогда есть элегантное, динамическое программирование линейного решения времени:
Ответ 3
Попробуйте использовать следующий код:
#include <stdio.h>
int main(void) {
int arr[] = {-11,-2,3,-1,2,-9,-4,-5,-2, -3};
int cur = arr[0] >= 0? arr[0] : 0, max = arr[0];
int start = 0, end = 0;
int i,j = cur == 0 ? 1 : 0;
printf("Cur\tMax\tStart\tEnd\n");
printf("%d\t%d\t%d\t%d\n",cur,max,start,end);
for (i = 1; i < 10; i++) {
cur += arr[i];
if (cur > max) {
max = cur;
end = i;
if (j > start) start = j;
}
if (cur < 0) {
cur = 0;
j = i+1;
}
printf("%d\t%d\t%d\t%d\n",cur,max,start,end);
}
getchar();
}
Ответ 4
Я предполагаю, что вы имеете в виду длинную возрастающую подпоследовательность.
Для этого нет решения O(n)
.
Очень наивным решением было бы создать дублирующий массив, отсортировать его в O(NlogN)
, а затем найти LCS
отсортированного массива и исходного массива, который принимает O(N^2)
.
Также существует прямое решение на основе DP, аналогичное LCS
, которое также принимает O(N^2)
, которое вы можете увидеть здесь здесь.
Но если вы имели в виду самую длинную возрастающую последовательность (последовательную). Это можно сделать в O(n)
.
Ответ 5
void longsub(int a[], int len) {
int localsum = INT_MIN;
int globalsum = INT_MIN;
int startindex = 0,i=0;
int stopindex = 0;
int localstart = 0;
for (i=0; i < len; i++) {
if (localsum + a[i] < a[i]) {
localsum = a[i];
localstart = i;
}
else {
localsum += a[i];
}
if (localsum > globalsum) {
startindex = localstart;
globalsum = localsum;
stopindex = i;
}
}
printf ("The begin and end indices are %d -> %d (%d).\n",startindex, stopindex, globalsum);
}
Ответ 6
Эта проблема может быть решена двумя разными способами.
Первый подход имеет две переменные, называемые sum
и MaxSum
.
-
Мы продолжим добавлять значения к сумме и будем сравнивать с MaxSum, если значение для суммы больше MaxSum - присвоит значение MaxSum
-
Если во время процесса значение для суммы будет ниже 0, мы будем reset сумму и начнем добавлять новый номер из следующего индекса. Пример кода для вышеуказанного решения представлен ниже:
private static void FindMaxSum(int[] array) { int sum = 0; int MaxSum = 0; for (int i = 0; i < array.Length; i++) { sum += array[i]; if (sum > MaxSum) { MaxSum = sum; } else if (sum < 0) { sum = 0; } } Console.WriteLine("Maximum sum is: " + MaxSum); }
Второй подход к решению этой проблемы состоит в том, что мы пройдем каждый элемент в массиве. Мы будем иметь те же 2 переменных суммы и MaxSum.
-
Сначала мы сравним добавление суммы со следующим элементом массива и самой суммой. Кто когда-либо больше - это значение будет храниться в переменной суммы.
-
Далее мы сравним значения sum и MaxSum и того, кто имеет большее значение - мы сохраним это значение в переменной MaxSum. Пример кода приведен ниже:
private static void FindMaxSum(int[] array) { int sum = array[0], Maxsum = array[0]; for (int i = 1; i < array.Length; i++) { sum = Max(sum + array[i], array[i]); Maxsum = Max(sum, Maxsum); } Console.WriteLine("Maximum sum is: " + Maxsum); } private static int Max(int a, int b) { return a > b ? a : b; }
Ответ 7
Если вы спрашиваете, что такое непрерывная подпоследовательность, для которой максимальная сумма, я обнаружил до сих пор 4 альго: -
-
Brute-force: найдите все возможные суммы с помощью вложенных циклов и продолжайте обновлять maxSum, если вы найдете сумму, большую, чем предыдущее установленное значение maxSum. Сложность времени равна O (n ^ 2)
-
Решение динамического программирования: это замечательно изящное решение, которое я нашел на самом StackOverflow - fooobar.com/questions/57701/... - Сложность времени: O (n), Сложность пространства: O (n)
-
DP без памяти - алгоритм Кадане - https://en.wikipedia.org/wiki/Maximum_subarray_problem - Сложность времени: O (n), Сложность пространства: O (1)
-
Разделить и разрешить решение - http://eecs.wsu.edu/~nroy/courses/CptS223/notes/MaxSubsequenceSum.pdf Сложность времени: O (nlgn)
Ответ 8
Функция C выглядит так:
int largest(int arr[], int length)
{
int sum= arr[0];
int tempsum=0;
for(int i=0;i<length;i++){
tempsum+=arr[i];
if(tempsum>sum)
sum=tempsum;
if(tempsum<0)
tempsum=0;
}
return sum;
}