Szukaj…


Podstawowe informacje na temat algorytmu maksymalnej podtablicy

Problemem maksymalnej podtablicy jest metoda znajdowania ciągłej podtablicy w jednowymiarowej tablicy liczb, która ma największą sumę.

Problem został pierwotnie zaproponowany przez Ulfa Grenandera z Uniwersytetu Browna w 1977 r. Jako uproszczony model szacowania maksymalnego prawdopodobieństwa wzorców na zdigitalizowanych obrazach.

Możemy mieć taki problem, rozważmy listę różnych liczb całkowitych. Możemy być zainteresowani tym, który całkowicie sąsiadujący podzbiór będzie miał największą sumę. Na przykład, jeśli mamy tablicę [0, 1, 2, -2, 3, 2] , maksymalna podtablica wynosi [3, 2] , z sumą 5 .

Podejście Brute-Force do rozwiązania:

Ta metoda jest najbardziej nieefektywna w znalezieniu rozwiązania. W ten sposób przejdziemy przez każdą możliwą podtablicę, a następnie znajdziemy sumę wszystkich z nich. Na koniec porównaj wszystkie wartości i znajdź maksymalną podtablicę.

Pseudo-kod dla Brute-Force Approach:

MaxSubarray(array)
  maximum = 0
  for i in input
    current = 0
    for j in input
       current += array[j]
       if current > maximum
         maximum = current
  return maximum

Złożoność czasowa dla metody Brute-Force wynosi O(n^2) . Przejdźmy więc do dzielenia i podbijania podejścia.

Podejmij podział i podbij rozwiązanie:

Znajdź sumę podrzędnych po lewej stronie, podrzędnych po prawej. Następnie przejrzyj wszystkie te, które przekraczają podział środkowy, i na koniec zwróć maksymalną sumę. Ponieważ jest to algorytm dzielenia i zdobywania, musimy mieć dwie różne funkcje.

Pierwszy to krok dzielenia,

maxSubarray(array)
  if start = end
    return array[start]
  else
    middle = (start + end) / 2
    return max(maxSubarray(array(From start to middle)), maxSubarray(array(From middle + 1 to end)), maxCrossover(array))

W drugiej części oddziel różne części, które są tworzone w pierwszej części.

maxCrossover(array)
  currentLeftSum = 0
      leftSum = 0
  currentRightSum = 0
      rightSum = 0
  for i in array
    currentLeftSum += array[i]
    if currentLeftSum > leftSum
      leftSum = currentLeftSum
  for i in array
    currentRightSum += array[i]
    if currentRightSum > rightSum
      rightSum = currentRightSum
  return leftSum + rightSum

Złożoność czasowa dla metody Dziel i rządź wynosi O(nlogn) . Przejdźmy więc do programowania dynamicznego.

Dynamiczne podejście do programowania:

To rozwiązanie jest również znane jako Algorytm Kadane'a. Jest to liniowy algorytm czasu. To rozwiązanie podaje Joseph B. Kadane pod koniec lat 70.

Ten algorytm po prostu przechodzi przez pętlę, ciągle zmieniając bieżącą maksymalną sumę. Co ciekawe, jest to bardzo prosty przykład algorytmu programowania dynamicznego, ponieważ wymaga nakładającego się problemu i zmniejsza go, abyśmy mogli znaleźć bardziej wydajne rozwiązanie.

Pseudo-kod algorytmu Kadane'a:

MaxSubArray(array)
  max = 0
  currentMax = 0
  for i in array
    currentMax += array[i]
    if currentMax < 0
      currentMax = 0
    if max < currentMax
      max = currentMax
  return max

Złożoność czasowa algorytmu Kadane'a wynosi O(n) .

Implementacja C #

public class MaximumSubarray
{
    private static int Max(int a, int b)
    {
        return a > b ? a : b;
    }

    static int MaxSubArray(int[] input, int n)
    {
        int max = input[0];
        int currentMax = input[0];
        for (int i = 1; i < n; i++)
        {
            currentMax = Max(input[i], currentMax + input[i]);
            max = Max(max, currentMax);
        }
        return max;
    }

    public static int Main(int[] input)
    {
        int n = input.Length;
        return MaxSubArray(input, n);
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow