Kadane алгоритм объяснил

может кто-нибудь провести меня через то, что происходит здесь, в алгоритме Кадана? Хотел проверить мое понимание. вот как я это вижу.

вы перебираете массив, и каждый раз, когда вы устанавливаете переменную ans на наибольшее значение, пока это значение не станет отрицательным, тогда ans станет нулем.

в то же время переменная sum перезаписывается каждый раз через цикл, до максимума между ранее увиденными суммами или самыми большими " ans " до сих пор. Как только петля закончено выполнение у вас будет самая большая сумма или ответ видели до сих пор!

var sumArray = function(array) {
      var ans = 0;
      var sum = 0;
      //loop through the array.


      for (var i = 0; i < array.length; i++) {
        //this is to make sure that the sum is not negative. 
        ans = Math.max(0, ans + array[i]);

        //set the sum to be overwritten if something greater appears.
        sum = Math.max(sum, ans)
      }

      return sum;

    };

5 ответов


рассмотрим трассировку значений:

var maximumSubArray = function(array) {
    var ans = 0;
    var sum = 0;

    console.log(ans, sum);
    for (var i = 0; i < array.length; i++) {

        ans = Math.max(0, ans + array[i]);
        sum = Math.max(sum, ans);
        console.log(ans, sum, array[i]);
    }
    console.log(ans, sum);
    return sum;

};

maximumSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4]);

принты:

0 0
0 0 -2
1 1 1
0 1 -3
4 4 4
3 4 -1
5 5 2
6 6 1
1 6 -5
5 6 4
5 6

первая колонка -ans, который является суммой текущего поддиапазона. Второй -sum, представляющий собой сумму величайших увиденных до сих пор. Третий элемент, который только что был посещен. Вы можете увидеть, что непрерывный подмассив с максимальной суммой является 4, −1, 2, 1, С суммы 6.

пример из Википедия.

далее перевод кода, приведенного в Википедии под абзацем: "вариация задачи, которая не позволяет возвращать подмножества нулевой длины, в случае, если весь массив состоит из отрицательных чисел, может быть решена со следующим кодом:"

var maximumSubArray = function(array) {
    var ans = array[0];
    var sum = array[0];

    console.log(ans, sum);
    for (var i = 1; i < array.length; i++) {

        ans = Math.max(ans, ans + array[i]);
        sum = Math.max(sum, ans);
        console.log(ans, sum, array[i]);
    }
    console.log(ans, sum);
    return sum;

};

видим, что:

> maximumSubArray([-10, -11, -12])
-10 -10
-10 -10 -11
-10 -10 -12
-10 -10
-10

последнее число является ожидаемым результатом. Остальные-как в предыдущем примере.


Это позаботится как о смешанном массиве ситуаций, так и обо всем массиве отрицательных чисел.

var maximumSubArray = function(arr) {
    var max_cur=arr[0], max_global = arr[0];
    for (var i = 1; i < arr.length; i++) {
        max_cur = Math.max(arr[i], max_cur + arr[i]);
        max_global = Math.max(max_cur, max_global);
    }  
    return max_global;
};
console.log(maximumSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4]));
console.log(maximumSubArray([-10, -11, -12]));

посмотреть этой ссылке, это дает четкое объяснение алгоритма Кадане.

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

следующий код обрабатывает случай, когда все числа отрицательный.

int maxSubArray(int a[], int size)
{
   int max_so_far = a[0], i;
   int curr_max = a[0];

   for (i = 1; i < size; i++)
   {
        curr_max = max(a[i], curr_max+a[i]);
        max_so_far = max(max_so_far, curr_max);
   }
   return max_so_far;
}

Я также сделал усиление алгоритма Кадана для всех отрицательных чисел в массиве.

int maximumSubSum(int[] array){
        int currMax =0;
        int maxSum = 0;

        //To handle All negative numbers
        int max = array[0];
        boolean flag = true;
        for (int i = 0; i < array.length; i++) {

             //To handle All negative numbers to get at least one positive number
            if(array[i]<0)
                max= Math.max(max , array[i]);
            else
                flag = false;


            currMax = Math.max(0, currMax + array[i]);
            maxSum = Math.max(maxSum , currMax);
        }
        return flag?max:sum;
    }

Тестовый Случай: -30 -20 -10

-10

-10 -20 -30

-10

-2 -3 4 -1 -2 1 5 -3

7


Я бы предпочел более функциональный способ в JavaScript:

const maximumSubArray = function(array) {
  return array.reduce(([acc, ans], x, i) => { 
    ans = Math.max(0, ans + x);
    return [Math.max(acc, ans), ans];
  }, [array[0],array[0]])[0];
};

cl(maximumSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4])); // 6