📜  使总和可被 3 整除的数组中的分割数最大化

📅  最后修改于: 2021-09-17 16:00:42             🧑  作者: Mango

给定一个大小为N的整数数组arr 。任务是找到最大分割数,使得每个分割的总和可以被3整除。没有必要所有的分裂都可以被3整除,任务只是最大化可以被3整除的分裂数。
例子:

方法
一个可以轻松得出的观察结果是,如果我们对每个元素取模 3,则更容易处理数组。因为它不会对拆分产生任何影响。现在这个问题可以使用动态规划来解决。

  1. dp[i]表示位置i处的最大分割数。
  2. 然后计算前缀和模 3。
  3. 因此,如果一个段的总和可被 3 整除,则其左右前缀总和也将相同。
  4. 另一件要注意的事情是前缀和模 3 可以是 0、1 或 2。因此,如果当前前缀和模 3 为 1。选择左指针作为最右边的索引,其前缀和为 1。或者忽略该段并继续。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include
using namespace std;
 
int calculate_maximum_splits(int arr[], int N)
{
     
    // Prefix array storing right most
    // index with prefix sums 0, 1, 2
    int pre[] = { 0, -1, -1 };    
 
    // dp array
    int dp[N];
    memset(dp, 0, sizeof(dp));
     
    // Current prefix sum
    int C = 0;
 
    for(int i = 0; i < N; i++)
    {
       C = C + arr[i];
        
       // Calculating the prefix sum modulo 3
       C = C % 3;
        
       // We dont have a left pointer
       // with prefix sum C
       if (pre[C] == -1)
       {
           dp[i] = dp[i - 1];
            
           // We cannot consider i as
           // a right pointer of any segment
       }
       else
       {
            
           // We have a left pointer
           // pre[C] with prefix sum C
           dp[i] = max(dp[i - 1], dp[pre[C]] + 1);
       }
        
       // i is the rightmost index of
       // prefix sum C
       pre[C] = i;
    }
    return dp[N - 1];
}
 
// Driver code
int main()
{
    int arr[] = { 2, 36, 1, 9, 2, 0, 1, 8, 1 };
    int N = sizeof(arr) / sizeof(arr[0]);
     
    cout << (calculate_maximum_splits(arr, N));
}
 
// This code is contributed by chitranayal


Java
// Java implementation of the above approach
import java.util.*;
 
class GFG{
 
static int calculate_maximum_splits(int arr[],
                                    int N)
{
     
    // Prefix array storing right most
    // index with prefix sums 0, 1, 2
    int pre[] = { 0, -1, -1 };    
 
    // dp array
    int[] dp = new int[N];
    Arrays.fill(dp, 0);
     
    // Current prefix sum
    int C = 0;
 
    for(int i = 0; i < N; i++)
    {
        C = C + arr[i];
             
        // Calculating the prefix sum modulo 3
        C = C % 3;
             
        // We dont have a left pointer
        // with prefix sum C
        if (pre[C] == -1)
        {
            if(1 <= i)
            dp[i] = dp[i - 1];
                 
            // We cannot consider i as
            // a right pointer of any segment
        }
        else
        {
             
            // We have a left pointer
            // pre[C] with prefix sum C
            dp[i] = Math.max(dp[i - 1],
                             dp[pre[C]] + 1);
        }
         
        // i is the rightmost index of
        // prefix sum C
        pre[C] = i;
    }
    return dp[N - 1];
}
 
// Driver code
public static void main(String[] args)
{
    int arr[] = { 2, 36, 1, 9, 2, 0, 1, 8, 1 };
    int N = arr.length;
 
    System.out.println(calculate_maximum_splits(arr, N));
}
}
 
// This code is contributed by offbeat


Python3
# Python3 program for above approach
def calculate_maximum_splits(arr, N):
 
    # prefix array storing right most
    # index with prefix sums 0, 1, 2
    pre =[0, -1, -1]        
 
    # dp array
    dp =[0 for i in range(N)]
    # current prefix sum
    C = 0
 
    for i in range(N):
 
        C = C + arr[i]
 
        # Calculating the prefix sum modulo 3
        C = C % 3
 
        # We dont have a left pointer
        # with prefix sum C
        if pre[C]==-1:
 
            dp[i]= dp[i-1]
            # We cannot consider i as
            # a right pointer of any segment
        else:
            # We have a left pointer
            # pre[C] with prefix sum C
            dp[i]= max(dp[i-1], dp[pre[C]]+1)
 
        # i is the rightmost index of
        # prefix sum C
        pre[C]= i
 
    return dp[N-1]
# Driver code
arr = [2, 36, 1, 9, 2, 0, 1, 8, 1]
N = len(arr)
print(calculate_maximum_splits(arr, N))


C#
// C# implementation of the above approach
using System;
 
class GFG{
 
static int calculate_maximum_splits(int []arr,
                                    int N)
{
     
    // Prefix array storing right most
    // index with prefix sums 0, 1, 2
    int []pre = { 0, -1, -1 };    
 
    // dp array
    int[] dp = new int[N];
    for(int i = 0; i < N; i++)
    {
        dp[i] = 0;
    }
     
    // Current prefix sum
    int C = 0;
 
    for(int i = 0; i < N; i++)
    {
        C = C + arr[i];
             
        // Calculating the prefix sum modulo 3
        C = C % 3;
             
        // We dont have a left pointer
        // with prefix sum C
        if (pre[C] == -1)
        {
            if(1 <= i)
            dp[i] = dp[i - 1];
                 
            // We cannot consider i as
            // a right pointer of any segment
        }
        else
        {
             
            // We have a left pointer
            // pre[C] with prefix sum C
            dp[i] = Math.Max(dp[i - 1],
                             dp[pre[C]] + 1);
        }
         
        // i is the rightmost index of
        // prefix sum C
        pre[C] = i;
    }
    return dp[N - 1];
}
 
// Driver code
public static void Main(string[] args)
{
    int []arr = { 2, 36, 1, 9, 2, 0, 1, 8, 1 };
    int N = arr.Length;
 
    Console.Write(calculate_maximum_splits(arr, N));
}
}
 
// This code is contributed by rutvik_56


Javascript


输出:
4

时间复杂度: O (N)
辅助空间: O(N)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程