Найти подпоследовательность с наибольшей суммой элементов в массиве

Недавно я беседовал с компанией, и они попросили меня написать алгоритм, который найдет подпоследовательность с наибольшей суммой элементов в массиве. Элементы массива могут быть отрицательными. Для этого существует 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.

Если, с другой стороны, вы имеете в виду поиск вспомогательного массива с максимальной суммой (имеет смысл только с отрицательными значениями), тогда есть элегантное, динамическое программирование линейного решения времени:

http://en.wikipedia.org/wiki/Maximum_subarray_problem

Ответ 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;
}