Kadence 算法:最大子数组和

什么是最大的连续子数组和?

子数组是数组的连续部分。它可以是数组的单个元素,也可以是数组的一部分。最大的连续子数组和意味着具有最大和值的子数组。

例如,一个数组是{-10, 5, 1, 6, -9, 2, -7, 3, -5}。它的子数组可以是:{-10,5,1,6}或{5,1,6}或{2,7,3, -5}等。但{5,1,6,3}不能是子数组,因为它们不保持序列。

Largest Sum Contiguous Subarray

如果您注意到,在所有子数组中,以下突出显示的子数组(5,1,6)具有最大的求和值。

Largest Sum Contiguous Subarray

子数组 {5,1,6} 的和 = 11,是上述数组所有可能的子数组组合中的最大和。因此,对于上述数组,最大子数组是 {5,1,6}。

Kadence 算法:最大子数组和

求解最大连续子数组和的简单方法

解决这个问题的简单方法是使用两个循环来查找所有子数组,计算它们的和,然后找到最大值。

这是查找最大连续子数组和的简单方法的流程图。这是一种蛮力方法,因为我们遍历了所有可能的子数组。

Simple approach to Solving the Largest Sum

以下是执行此操作的简单步骤。

步骤 1) 将 max_sum 初始化为最小整数值,并将变量“begin”和“end”设置为零。

步骤 2) 令 i 和 j 为数组的索引,其中“j”大于等于“i”。i 代表子数组的起始索引,j 代表子数组的结束索引。

步骤 3) “Current_sum”将保存子数组的和。计算当前和后,检查 current_sum 是否大于 max_sum。

步骤 4) 如果 current_sum 更大,则将 max_sum 替换为当前和。

步骤 5) 检查“j”是否已到达数组末尾。如果“j”已到达数组末尾,则增加“i”并将 current_sum 值更改为 0。

步骤 6) 执行所有这些步骤,直到“i”到达数组末尾。

步骤 7) 在这两个循环结束后,max_sum 将保存最大的子数组和。

简单方法的伪代码

  function maximumSubarraySum():
    input: array
  for all possible subArray from array:
    calculate sum of each sub array
    store the maximum subArray
  return the maximum sum

简单方法的C++实现

#include <stdio.h>
#include <iostream>
using namespace std;
void maximumSubarraySum(int array[], int n) {
  int max_sum = -1e9;
  int begin = 0;
  int end = 0;
  for (int i = 0; i < n; i++) {
    int current_sum = 0;
    for (int j = i; j < n; j++) {
      current_sum += array[j];
      if (max_sum < current_sum) {
        max_sum = current_sum;
        begin = i;
        end = j;
      }
    }
  }
  cout << "largest sum is " << max_sum << endl;
  cout << "largest sum contiguous subarray: ";
  for (int i = begin; i <= end; i++) {
    cout << array[i] << "\t";
  }
}
int main() {
  int array[] = {-10, 5, 1, 6, -9, 2, -7, 3, -5};
  maximumSubarraySum(array, sizeof(array) / sizeof(array[0]));
}

输出

largest sum is 12
largest sum contiguous subarray: 5      1       6

简单方法的Python实现

def maximumSubarraySum(numbers):
max_sum,begin,end = -1e9, 0 , 0
  for i in range(len(numbers)):
    current_sum=0
  for j in range(i,len(numbers)):
    current_sum+=numbers[j]
  if max_sum<current_sum:
    max_sum=current_sum
  begin,end=i,j
    print("largest sum is ",max_sum)
    print("largest sum contiguous subarray: ",end="")
  for i in range(begin,end+1):
    print(numbers[i],end='\t')
    numbers = [-10,5,1,6,-9,2,-7,3,-5]
    maximumSubarraySum(numbers)

输出

largest sum is 12
largest sum contiguous subarray: 5      1       6

Kadane 算法寻找最大连续子数组和

Kadane 算法是一种“动态规划”方法。这里我们使用一个循环而不是两个循环。Kadane 算法的通用实现仅适用于正数数组。

我们只需要两个变量来找到最大的连续子数组和。这是 Kadane 算法的流程图。

Kadane’s Algorithm to Find the Largest Sum

以下是 Kadane 算法的步骤。

步骤 1) 创建两个变量:current_sum 和 max_sum。

“Current_sum”将保存以特定数组索引结尾的最大和值,而“max_sum”将保存到目前为止的最大求和值。

步骤 2) 我们将每个数组元素的值加到 current_sum 中。然后我们将检查以下两个条件:

  • 如果 current_sum 小于当前元素,则 current_sum 值将为当前元素。
  • 如果 max_sum 小于 current_sum,则 max_sum 将为 current_sum。

步骤 3) 对整个数组执行上一步,我们将在“max_sum”变量中得到最大的连续子数组和。

Kadane 算法示例

我们将使用一个小尺寸数组演示 Kadane 算法,并讨论查找最大连续子数组和的每个步骤。

假设给定的数组如下所示:

Example of Kadane’s Algorithm

以下是 Kadane 算法的步骤:

步骤 1) 创建两个变量:current_sum 和 max_sum。将 max_sum 设置为 INT_MIN,将 current_sum 设置为零。(此处,INT_MIN 表示最小整数数)。

步骤 2) 在索引 0 处,值为 4。所以,current_sum = 0 + 4 或 4。此时 current_sum 大于 max_sum,max_sum 将为 4。

Example of Kadane’s Algorithm

步骤 3) 在索引 1 处,值为 -2。所以,current_sum = 4 + (-2) 或 2。

此时 current_sum 小于 max_sum。因此,max_sum 的值不会被更新。

Example of Kadane’s Algorithm

步骤 4) 下一个值是 1。如果我们将其与 current_sum 相加,则 current_sum 将为 3。此时 max_sum 仍然大于 current_sum。因此,max_sum 不会更新。

Example of Kadane’s Algorithm

步骤 5) 在索引 3 处,值为 3。我们将通过将 current_sum 增加 3 来更新值。所以,current_sum 将为 6。

Example of Kadane’s Algorithm

在这种情况下,max_sum 小于 current_sum。因此,max_sum 将被 current_sum 的值更新。

步骤 6) 对于数组的最后一个元素,我们有 -1。如果我们将其与 current_sum 相加,current_sum 将为 5,小于 max_sum。因此,max_sum 将保持为 6。

Example of Kadane’s Algorithm

我们已经到达了数组的末尾,算法在此结束。现在,“max_sum”包含最大的子数组和。即 5。子数组是 {4,-2,1,3}。

Kadane 算法的伪代码

function KadaneAlgorithm():
    input: array
    maximum_sum, current_sum = 0
    for each elements in array:
        add the element with current_sum
        if current_sum is greater than the maximum_sum
            then maximum_sum = current_sum
        if current_sum is less than the element
            then current_sum = element
    return the value of maximum_sum

Kadane 算法的 C++ 实现

#include < iostream >
using namespace std;
void kadane(int array[], int n) {
  int current_sum = 0;
  int max_sum = -1e9;
  // -1e9 means -10000000
  for (int i = 0; i < n; i++) {
    current_sum += array[i];
    if (max_sum < current_sum) {
      max_sum = current_sum;
    }
    if (current_sum < array[i]) {
      current_sum = array[i];
    }
  }
  cout << "largest sum is " << max_sum << endl;
}
int main() {
  int array[] = {-10, 5, 1, 6, -9, 2, -7, 3, -5};
  kadane(array, sizeof(array) / sizeof(array[0]));
}

输出

largest sum is 12

Kadane 算法的 Python 实现

def kadane(numbers):
  current_sum = 0
  max_sum = -1e9
for i in range(len(numbers)):
  current_sum += numbers[i]
if max_sum < current_sum:
  max_sum = current_sum
if current_sum<numbers[i]:
  current_sum = numbers[i]
  print("largest sum is ",max_sum)
  kadane([-10,5,1,6,-9,2,-7,3,-5])

输出

largest sum is 12

最大连续子数组和的复杂度分析

简单方法使用两个循环。该方法计算所有可能的子数组和以找到最大的一个。这是一种蛮力方法。每个循环都会运行直到数组的末尾。

如果一个数组总共有 N 个元素,那么使用两个循环,我们将遍历 N2 个元素。因此,查找最大连续子数组和的简单方法的 time complexity 将是 O(N2)这里,“O”表示复杂度函数。

另一方面,Kadane 算法是用于查找最大连续子数组和的动态规划方法。如果您遵循示例或代码,您会发现我们只使用了一个循环。

因此,如果输入数组的大小为 N,则 Kadane 算法的时间复杂度为 O(N)。这比简单方法更快。例如,一个包含 100 个元素的数组。简单方法将需要 100*100 或 10,000 个 CPU 时间。但 Kadane 算法只需要 100 个 CPU 时间。