📌  相关文章
📜  最大化总和可被3整除的数组中的拆分数

📅  最后修改于: 2021-05-17 22:28:43             🧑  作者: 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 appraoch
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 appraoch
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)