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:
- The size of subarray is 1.
- The sum of elements of that subarray is at least K.
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:
- Declare prefix array pre[N + 1] such that pre[i] stores the prefix sum till ith element.
- Declare dp[N + 1][N + 1] and for every i from 0 to N update dp[i][i] as 1
-
To calculate answer for smaller subarrays, iterate from 1 to N as size and check for all values of i and j:
- dp[i][j] = (dp[i][j] | dp[i][k] & dp[k + 1][j]) (splitting array for each k from i to j – 1)
- Return dp[1][N] (which is answer whether array arr[] can be partitioned in N subarrays)
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> |
1
Time Complexity: O(N3), where N is the size of input array arr[].
Auxiliary Space: O(N2)