Open In App

Split the array into N subarrays where each subarray has size 1 or sum at least K

Given an array arr[] of size N and integer K. Task for this problem is to check if given array can be split into N continuous subarrays by performing given operations. In one operation choose existing array which may be result of previous operation and split it into two subarrays with each of subarray follows at least one of the following properties:

Examples:



Input: arr[] = {2, 3, 3, 2, 3}, K = 6
Output: 1
Explanation:

  • In first operation partition {2, 3, 3, 2, 3} into {2, 3, 3, 2} + {3} each partitioned subarray satisfies required property. Subarrays are {{2, 3, 3, 2} + {3}}
  • In second operation partition {2, 3, 3, 2} into {2, 3, 3} + {2} each partitioned subarray satisfies required property. Subarrays are {{2, 3, 3} + {2} + {3}}
  • In third operation partition {2, 3, 3} into {2} + {3, 3} each partitioned subarray satisfies required property. Subarrays are {{2} + {3, 3} + {2} + {3}}
  • In fourth operation partition {3, 3} into {3} + {3} each partitioned subarray satisfies required property. Subarrays are {{2} + {3} + {3} + {2} + {3}}

so, it is possible to split given subarray into N subarrays.



Input: arr[] = {2, 1, 3}, K = 5
Output: 0
Explanation: Array arr[] cannot be partitioned into N = 3 subarrays by performing any operation

Approach: Implement the idea below to solve the problem:

Dynamic Programming can be used to solve this problem. The main concept of DP in the problem will be:

DP[i][j] will store whether it is possible to partition subarray from i to j (arr[i], arr[i + 1]……, arr[j])

Transition:

dp[i][j] = (dp[i][j] | dp[i][k] & dp[k + 1][j]) (splitting array for each k from i to j – 1)

Bitwise AND operation is used so when both arrays dp[i][k] and dp[k + 1][j] satisfies required property then only dp[i][j] will be 1. Also, to make sure while partitioning either one of above conditions is being satisfied by partitioned subarrays.

To check if partitioned subarray has sum at least K prefix sum array will be used.

Step-by-step algorithm:

Below is the implementation of the above approach:




// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to Check if array can be partitioned in N
// subarrays such that after each operation every partition
// have sum at least K or size 1
int isPartitionPossible(int arr[], int N, int K)
{
 
    // prefix sum array
    vector<int> pre(N + 1, 0);
 
    // filling prefix sum array
    for (int i = 1; i <= N; i++)
        pre[i] = arr[i - 1];
 
    // taking prefix sum
    for (int i = 1; i <= N; i++) {
        pre[i] = pre[i] + pre[i - 1];
    }
 
    // DP array initalized with 0
    vector<vector<int> > dp(N + 1, vector<int>(N + 1, 0));
 
    // Base Case
    for (int i = 0; i <= N; i++)
        dp[i][i] = 1;
 
    // iterating on each size of subarray
    for (int size = 1; size <= N; size++) {
 
        // iterating for start i
        for (int i = 1; i <= N - size + 1; i++) {
 
            // finding answer for array arr[i:j]
            int j = i + size - 1;
 
            // partitioning string at position k
            for (int k = i; k < j; k++) {
 
                // either one of the required property
                // should be true for paritioned subarrays
                if ((k - i == 0 or pre[k] - pre[i - 1] >= K)
                    and (j - k - 1 == 0
                         or pre[j] - pre[k] >= K))
 
                    // update dp table according to
                    // transitions
                    dp[i][j]
                        = (dp[i][j]
                           | (dp[i][k] & dp[k + 1][j]));
            }
        }
    }
 
    // returning final answer whether it is possible to
    // parition given array in N subarrays
    return dp[1][N];
}
 
// Driver Code
int main()
{
 
    // Input
    int N = 5, K = 6;
    int arr[] = { 2, 3, 3, 2, 3 };
 
    // Function Call
    cout << isPartitionPossible(arr, N, K) << endl;
 
    return 0;
}




public class Main {
    // Function to check if partition is possible
    static boolean isPartitionPossible(int[] arr, int N,
                                       int K)
    {
        // Prefix sum array
        int[] pre = new int[N + 1];
 
        // Filling prefix sum array
        for (int i = 1; i <= N; i++) {
            pre[i] = arr[i - 1];
        }
 
        // Taking prefix sum
        for (int i = 1; i <= N; i++) {
            pre[i] = pre[i] + pre[i - 1];
        }
 
        // DP array initialized with 0
        boolean[][] dp = new boolean[N + 1][N + 1];
 
        // Base Case
        for (int i = 0; i <= N; i++) {
            dp[i][i] = true;
        }
 
        // Iterating on each size of subarray
        for (int size = 1; size <= N; size++) {
 
            // Iterating for start i
            for (int i = 1; i <= N - size + 1; i++) {
 
                // Finding answer for array arr[i:j]
                int j = i + size - 1;
 
                // Partitioning string at position k
                for (int k = i; k < j; k++) {
 
                    // Either one of the required property
                    // should be true for partitioned
                    // subarrays
                    if ((k - i == 0
                         || pre[k] - pre[i - 1] >= K)
                        && (j - k - 1 == 0
                            || pre[j] - pre[k] >= K)) {
 
                        // Update dp table according to
                        // transitions
                        dp[i][j]
                            = dp[i][j]
                              || (dp[i][k] && dp[k + 1][j]);
                    }
                }
            }
        }
 
        // Returning final answer whether it is possible to
        // partition the given array into N subarrays
        return dp[1][N];
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Input
        int N = 5;
        int K = 6;
        int[] arr = { 2, 3, 3, 2, 3 };
 
        // Function Call
        System.out.println(isPartitionPossible(arr, N, K));
    }
}




def is_partition_possible(arr, N, K):
    # prefix sum array
    pre = [0] * (N + 1)
 
    # filling prefix sum array
    for i in range(1, N + 1):
        pre[i] = arr[i - 1]
 
    # taking prefix sum
    for i in range(1, N + 1):
        pre[i] = pre[i] + pre[i - 1]
 
    # DP array initialized with 0
    dp = [[0] * (N + 1) for _ in range(N + 1)]
 
    # Base Case
    for i in range(N + 1):
        dp[i][i] = 1
 
    # iterating on each size of subarray
    for size in range(1, N + 1):
 
        # iterating for start i
        for i in range(1, N - size + 2):
 
            # finding answer for array arr[i:j]
            j = i + size - 1
 
            # partitioning string at position k
            for k in range(i, j):
 
                # either one of the required property
                # should be true for partitioned subarrays
                if ((k - i == 0 or pre[k] - pre[i - 1] >= K) and
                        (j - k - 1 == 0 or pre[j] - pre[k] >= K)):
 
                    # update dp table according to transitions
                    dp[i][j] = dp[i][j] | (dp[i][k] & dp[k + 1][j])
 
    # returning final answer whether it is possible to
    # partition given array into N subarrays
    return dp[1][N]
 
 
# Driver Code
if __name__ == "__main__":
    # Input
    N = 5
    K = 6
    arr = [2, 3, 3, 2, 3]
 
    # Function Call
    print(is_partition_possible(arr, N, K))




using System;
 
class GFG
{
    // Function to check if array can be partitioned in N
    // subarrays such that after each operation every partition
    // has sum at least K or size 1
    static int IsPartitionPossible(int[] arr, int N, int K)
    {
        // Prefix sum array
        int[] pre = new int[N + 1];
 
        // Filling prefix sum array
        for (int i = 1; i <= N; i++)
            pre[i] = arr[i - 1];
 
        // Taking prefix sum
        for (int i = 1; i <= N; i++)
            pre[i] = pre[i] + pre[i - 1];
 
        // DP array initialized with 0
        int[,] dp = new int[N + 1, N + 1];
 
        // Base Case
        for (int i = 0; i <= N; i++)
            dp[i, i] = 1;
 
        // Iterating on each size of subarray
        for (int size = 1; size <= N; size++)
        {
            // Iterating for start i
            for (int i = 1; i <= N - size + 1; i++)
            {
                // Finding answer for array arr[i:j]
                int j = i + size - 1;
 
                // Partitioning string at position k
                for (int k = i; k < j; k++)
                {
                    // Either one of the required property
                    // should be true for partitioned subarrays
                    if ((k - i == 0 || pre[k] - pre[i - 1] >= K)
                        && (j - k - 1 == 0 || pre[j] - pre[k] >= K))
                    {
                        // Update dp table according to transitions
                        dp[i, j] = (dp[i, j] | (dp[i, k] & dp[k + 1, j]));
                    }
                }
            }
        }
 
        // Returning final answer whether it is possible to
        // partition the given array in N subarrays
        return dp[1, N];
    }
 
    // Driver Code
    static void Main()
    {
        // Input
        int N = 5, K = 6;
        int[] arr = { 2, 3, 3, 2, 3 };
 
        // Function Call
        Console.WriteLine(IsPartitionPossible(arr, N, K));
    }
}




<script>
 
function isPartitionPossible(arr, N, K) {
    // Prefix sum array with an additional initial 0 for ease of calculation
    let pre = new Array(N + 1).fill(0);
 
    // Filling prefix sum array
    for (let i = 1; i <= N; i++) {
        pre[i] = arr[i - 1];
    }
 
    // Taking prefix sum
    for (let i = 1; i <= N; i++) {
        pre[i] = pre[i] + pre[i - 1];
    }
 
    // DP array initialized with false
    let dp = Array.from({ length: N + 1 }, () => Array(N + 1).fill(false));
 
    // Base Case
    for (let i = 0; i <= N; i++) {
        dp[i][i] = true;
    }
 
    // Iterating on each size of subarray
    for (let size = 1; size <= N; size++) {
        // Iterating for start i
        for (let i = 1; i <= N - size + 1; i++) {
            // Finding answer for array arr[i:j]
            let j = i + size - 1;
 
            // Partitioning string at position k
            for (let k = i; k < j; k++) {
                // Either one of the required property should be true for partitioned subarrays
                if ((k - i == 0 || pre[k] - pre[i - 1] >= K) && (j - k - 1 == 0 || pre[j] - pre[k] >= K)) {
                    // Update dp table according to transitions
                    dp[i][j] = dp[i][j] || (dp[i][k] && dp[k + 1][j]);
                }
            }
        }
    }
 
    // Returning final answer whether it is possible to partition the given array into subarrays
    return dp[1][N];
}
 
// Driver Code
let N = 5;
let K = 6;
let arr = [2, 3, 3, 2, 3];
 
// Function Call
console.log(isPartitionPossible(arr, N, K));
 
 
</script>

Output
1






Time Complexity: O(N3), where N is the size of input array arr[].
Auxiliary Space: O(N2)


Article Tags :