📜  最大子数组求和模m

📅  最后修改于: 2021-04-23 22:13:40             🧑  作者: Mango

给定一个由n个元素组成的数组和一个整数m。任务是找到其子阵列模m的总和的最大值,即找到每个子阵列mod m的总和并打印此模运算的最大值。
例子:

Input : arr[] = { 3, 3, 9, 9, 5 }
        m = 7
Output : 6
All sub-arrays and their value:
{ 9 } => 9%7 = 2
{ 3 } => 3%7 = 3
{ 5 } => 5%7 = 5
{ 9, 5 } => 14%7 = 2
{ 9, 9 } => 18%7 = 4
{ 3, 9 } => 12%7 = 5
{ 3, 3 } => 6%7 = 6
{ 3, 9, 9 } => 21%7 = 0
{ 3, 3, 9 } => 15%7 = 1
{ 9, 9, 5 } => 23%7 = 2
{ 3, 3, 9, 9 } => 24%7 = 3
{ 3, 9, 9, 5 } => 26%7 = 5
{ 3, 3, 9, 9, 5 } => 29%7 = 1

Input : arr[] = {10, 7, 18}
        m = 13
Output : 12
The subarray {7, 18} has maximum sub-array
sum modulo 13.

方法1(蛮力):
使用蛮力查找给定数组的所有子数组,并找到每个子数组mod m的总和,并跟踪最大值。
方法2(有效方法):
这个想法是计算数组的前缀和。我们找到以每个索引结尾的最大和,最后返回总的最大。要找到以index处的索引结尾的最大和,我们需要找到以i结尾的最大和的起点。以下步骤说明了如何找到起点。

Let prefix sum for index i be prefixi, i.e., 
prefixi = (arr[0] + arr[1] + .... arr[i] ) % m

Let maximum sum ending with i be, maxSumi. 
Let this sum begins with index j.

maxSumi = (prefixi - prefixj + m) % m
                   
From above expression it is clear that the
value of maxSumi becomes maximum when 
prefixj is greater than prefixi 
and closest to prefixi

以上算法主要有两个操作。

  1. 存储所有前缀。
  2. 对于当前前缀,前缀i ,找到大于或等于前缀i + 1的最小值。

对于上述操作,最适合使用自平衡二进制搜索树,例如AVL树,红黑树等。在下面的实现中,我们使用STL中的set实现自平衡二进制搜索树。
以下是此方法的实现:

C++
// C++ program to find sub-array having maximum
// sum of elements modulo m.
#include
using namespace std;
 
// Return the maximum sum subarray mod m.
int maxSubarray(int arr[], int n, int m)
{
    int x, prefix = 0, maxim = 0;
 
    set S;
    S.insert(0);   
 
    // Traversing the array.
    for (int i = 0; i < n; i++)
    {
        // Finding prefix sum.
        prefix = (prefix + arr[i])%m;
 
        // Finding maximum of prefix sum.
        maxim = max(maxim, prefix);
 
        // Finding iterator pointing to the first
        // element that is not less than value
        // "prefix + 1", i.e., greater than or
        // equal to this value.
        auto it = S.lower_bound(prefix+1);
 
        if (it != S.end())
            maxim = max(maxim, prefix - (*it) + m );
 
        // Inserting prefix in the set.
        S.insert(prefix);
    }
 
    return maxim;
}
 
// Driver Program
int main()
{
    int arr[] = { 3, 3, 9, 9, 5 };
    int n = sizeof(arr)/sizeof(arr[0]);
    int m = 7;
    cout << maxSubarray(arr, n, m) << endl;
    return 0;
}


Java
// Java program to find sub-array
// having maximum sum of elements modulo m.
import java.util.*;
class GFG
{
 
  // Return the maximum sum subarray mod m.
  static int maxSubarray(int[] arr, int n, int m)
  {
    int x = 0;
    int prefix = 0;
    int maxim = 0;
    Set S = new HashSet();
    S.add(0);
 
    // Traversing the array.
    for (int i = 0; i < n; i++)
    {
 
      // Finding prefix sum.
      prefix = (prefix + arr[i]) % m;
 
      // Finding maximum of prefix sum.
      maxim = Math.max(maxim, prefix);
 
      // Finding iterator poing to the first
      // element that is not less than value
      // "prefix + 1", i.e., greater than or
      // equal to this value.
      int it = 0;
 
      for (int j : S)
      {
        if (j >= prefix + 1)
          it = j;
      }
      if (it != 0)
      {
        maxim = Math.max(maxim, prefix - it + m);
      }
 
      // adding prefix in the set.
      S.add(prefix);
    }
    return maxim;
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    // Driver Code
    int[] arr = new int[] { 3, 3, 9, 9, 5 };
    int n = 5;
    int m = 7;
    System.out.print(maxSubarray(arr, n, m));
  }
}
 
// This code is contributed by pratham76.


Python3
# Python3 program to find sub-array
# having maximum sum of elements modulo m.
 
# Return the maximum sum subarray mod m.
def maxSubarray(arr, n, m):
 
    x = 0
    prefix = 0
    maxim = 0
 
    S = set()
    S.add(0)    
 
    # Traversing the array.
    for i in range(n):
 
        # Finding prefix sum.
        prefix = (prefix + arr[i]) % m
 
        # Finding maximum of prefix sum.
        maxim = max(maxim, prefix)
 
        # Finding iterator poing to the first
        # element that is not less than value
        # "prefix + 1", i.e., greater than or
        # equal to this value.
        it = 0
        for i in S:
            if i >= prefix + 1:
                it = i
        if (it != 0) :
                maxim = max(maxim, prefix - it + m )
 
        # adding prefix in the set.
        S.add(prefix)
 
    return maxim
 
# Driver Code
arr = [3, 3, 9, 9, 5]
n = 5
m = 7
print(maxSubarray(arr, n, m))
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)


C#
// C# program to find sub-array
// having maximum sum of elements modulo m.
using System;
using System.Collections;
using System.Collections.Generic;
 
class GFG
{
 
  // Return the maximum sum subarray mod m.
  static int maxSubarray(int[] arr, int n, int m)
  {
     
    int prefix = 0;
    int maxim = 0;
    HashSet S = new HashSet();
    S.Add(0);
 
    // Traversing the array.
    for (int i = 0; i < n; i++)
    {
 
      // Finding prefix sum.
      prefix = (prefix + arr[i]) % m;
 
      // Finding maximum of prefix sum.
      maxim = Math.Max(maxim, prefix);
 
      // Finding iterator poing to the first
      // element that is not less than value
      // "prefix + 1", i.e., greater than or
      // equal to this value.
      int it = 0;
 
      foreach(int j in S)
      {
        if (j >= prefix + 1)
          it = j;
      }
      if (it != 0)
      {
        maxim = Math.Max(maxim, prefix - it + m);
      }
 
      // adding prefix in the set.
      S.Add(prefix);
    }
    return maxim;
  }
 
  // Driver code
  public static void Main(string[] args)
  {
 
    int[] arr = new int[] { 3, 3, 9, 9, 5 };
    int n = 5;
    int m = 7;
    Console.Write(maxSubarray(arr, n, m));
  }
}
 
// This code is contributed by rutvik_56.


输出:

6