Given an array of positive integers arr[] and an integer k, you can remove either the leftmost or rightmost element from the array in one operation. After each operation, the size of arr[] is reduced by one. find the minimum number of operations required to make the total sum of the removed elements exactly equal to k. If it is impossible to achieve the sum k, return -1.
Examples :
Input: arr[] = [3, 4, 1, 3, 2], k = 5
Output: 2
Explanation: Removing 3 from left and 2 from right gives a sum of 5 in 2 operations.Input: arr[] = [5, 3, 4, 6, 2], k = 6
Output: -1
Explanation: It is impossible to achieve the sum of removed elements as 6.Input: arr[] = [1, 1, 3, 1, 2], k = 4
Output: 3
Explanation: Removing 1, 1 from left and 2 from right gives a sum of 4 in 3 operations.
Table of Content
[Naive Approach] Recursive Approach - O(2 ^ n) Time and O(n) Space
The idea is to use recursion to explore all combinations of removing elements from the left or right. In each recursive call, we have two choices: either to remove the left most element or remove the right most element. After exploring both the choices, return the minimum of the two. If all elements are exhausted, return -1.
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
int minRemovalsRec(vector<int> &arr, int k, int left, int right, int cnt) {
// Target sum achieved
if (k == 0)
return cnt;
// No elements left
if (left > right)
return INT_MAX;
// remove leftmost element
int l = minRemovalsRec(arr, k - arr[left], left + 1, right, cnt + 1);
// Remove rightmost element
int r = minRemovalsRec(arr, k - arr[right], left, right - 1, cnt + 1);
return min(l, r);
}
int minRemovals(vector<int> &arr, int k) {
int res = minRemovalsRec(arr, k, 0, arr.size() - 1, 0);
return res == INT_MAX ? -1 : res;
}
int main() {
vector<int> arr = {3, 4, 1, 3, 2};
int k = 5;
cout << minRemovals(arr, k) << endl;
return 0;
}
#include <limits.h>
#include <stdio.h>
int minRemovalsRec(int arr[], int k, int left, int right, int cnt) {
// Target sum achieved
if (k == 0)
return cnt;
// No elements left
if (left > right)
return INT_MAX;
// Remove leftmost element
int l = minRemovalsRec(arr, k - arr[left], left + 1, right, cnt + 1);
// Remove rightmost element
int r = minRemovalsRec(arr, k - arr[right], left, right - 1, cnt + 1);
return (l < r) ? l : r;
}
int minRemovals(int arr[], int k, int n) {
int res = minRemovalsRec(arr, k, 0, n - 1, 0);
return res == INT_MAX ? -1 : res;
}
int main() {
int arr[] = {3, 4, 1, 3, 2};
int k = 5;
int n = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", minRemovals(arr, k, n));
return 0;
}
class GfG {
static int minRemovalsRec(int[] arr, int k, int left, int right, int cnt) {
// Target sum achieved
if (k == 0)
return cnt;
// No elements left
if (left > right)
return Integer.MAX_VALUE;
// Remove leftmost element
int l = minRemovalsRec(arr, k - arr[left], left + 1, right, cnt + 1);
// Remove rightmost element
int r = minRemovalsRec(arr, k - arr[right], left, right - 1, cnt + 1);
return Math.min(l, r);
}
static int minRemovals(int[] arr, int k) {
int res = minRemovalsRec(arr, k, 0, arr.length - 1, 0);
return res == Integer.MAX_VALUE ? -1 : res;
}
public static void main(String[] args) {
int[] arr = {3, 4, 1, 3, 2};
int k = 5;
System.out.println(minRemovals(arr, k));
}
}
def minRemovalsRec(arr, k, left, right, cnt):
# Target sum achieved
if k == 0:
return cnt
# No elements left
if left > right:
return float('inf')
# Remove leftmost element
l = minRemovalsRec(arr, k - arr[left], left + 1, right, cnt + 1)
# Remove rightmost element
r = minRemovalsRec(arr, k - arr[right], left, right - 1, cnt + 1)
return min(l, r)
def minRemovals(arr, k):
res = minRemovalsRec(arr, k, 0, len(arr) - 1, 0)
return -1 if res == float('inf') else res
if __name__ == "__main__":
arr = [3, 4, 1, 3, 2]
k = 5
print(minRemovals(arr, k))
using System;
class GfG {
static int minRemovalsRec(int[] arr, int k, int left, int right, int cnt) {
// Target sum achieved
if (k == 0)
return cnt;
// No elements left
if (left > right)
return int.MaxValue;
// Remove leftmost element
int l = minRemovalsRec(arr, k - arr[left], left + 1, right, cnt + 1);
// Remove rightmost element
int r = minRemovalsRec(arr, k - arr[right], left, right - 1, cnt + 1);
return Math.Min(l, r);
}
static int minRemovals(int[] arr, int k) {
int res = minRemovalsRec(arr, k, 0, arr.Length - 1, 0);
return res == int.MaxValue ? -1 : res;
}
static void Main() {
int[] arr = { 3, 4, 1, 3, 2 };
int k = 5;
Console.WriteLine(minRemovals(arr, k));
}
}
function minRemovalsRec(arr, k, left, right, cnt) {
// Target sum achieved
if (k === 0)
return cnt;
// No elements left
if (left > right)
return Number.MAX_SAFE_INTEGER;
// Remove leftmost element
let l = minRemovalsRec(arr, k - arr[left], left + 1, right, cnt + 1);
// Remove rightmost element
let r = minRemovalsRec(arr, k - arr[right], left, right - 1, cnt + 1);
return Math.min(l, r);
}
function minRemovals(arr, k) {
let res = minRemovalsRec(arr, k, 0, arr.length - 1, 0);
return res === Number.MAX_SAFE_INTEGER ? -1 : res;
}
// Driver Code
const arr = [3, 4, 1, 3, 2];
const k = 5;
console.log(minRemovals(arr, k));
Output
2
[Better Approach] Using Prefix Array - O(n) Time and O(n) Space
If we observe carefully, we can say that after removing the elements whose sum = k, the sum of the remaining elements will be (total sum - k). Since we need to minimize the removals, the problem can be reduced to finding the longest subarray whose sum = (total sum - k).
We can find the longest subarray having sum = (total sum - k) by using a hash map or dictionary to store the first occurrence of each prefix sum. For each index i, we find the prefix sum till index i, say prefSum and find the first occurrence of (prefSum - (total sum - k)) in the hash map, if present. The difference between the first occurrence and the current index i will be the length of the subarray.
To know more about the algorithm, please refer Longest Subarray Having Sum K.
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
int minRemovals(vector<int> &arr, int k) {
int total = 0;
for (int num : arr)
total += num;
if(k == total)
return arr.size();
// Find the target sum for the longest subarray
int target = total - k;
unordered_map<int, int> prefIdx;
int prefSum = 0, maxLen = -1;
for (int i = 0; i < arr.size(); i++) {
prefSum += arr[i];
if(prefSum == target)
maxLen = i + 1;
else if (prefIdx.find(prefSum - target) != prefIdx.end())
maxLen = max(maxLen, i - prefIdx[prefSum - target]);
// Store prefix sum with its index
if(prefIdx.find(prefSum) == prefIdx.end())
prefIdx[prefSum] = i;
}
return maxLen == -1 ? -1 : arr.size() - maxLen;
}
int main() {
vector<int> arr = {3, 4, 1, 3, 2};
int k = 5;
cout << minRemovals(arr, k) << endl;
return 0;
}
import java.util.Map;
import java.util.HashMap;
class GfG {
static int minRemovals(int[] arr, int k) {
int total = 0;
for (int num : arr)
total += num;
if (k == total)
return arr.length;
// Find the target sum for the longest subarray
int target = total - k;
Map<Integer, Integer> prefIdx = new HashMap<>();
int prefSum = 0, maxLen = -1;
for (int i = 0; i < arr.length; i++) {
prefSum += arr[i];
if (prefSum == target)
maxLen = i + 1;
else if (prefIdx.containsKey(prefSum - target))
maxLen = Math.max(maxLen, i - prefIdx.get(prefSum - target));
// Store prefix sum with its index
if (!prefIdx.containsKey(prefSum))
prefIdx.put(prefSum, i);
}
return maxLen == -1 ? -1 : arr.length - maxLen;
}
public static void main(String[] args) {
int[] arr = {3, 4, 1, 3, 2};
int k = 5;
System.out.println(minRemovals(arr, k));
}
}
def minRemovals(arr, k):
total = 0
for num in arr:
total += num
if k == total:
return len(arr)
# Find the target sum for the longest subarray
target = total - k
prefIdx = {}
prefSum = 0
maxLen = -1
for i in range(len(arr)):
prefSum += arr[i]
if prefSum == target:
maxLen = i + 1
elif (prefSum - target) in prefIdx:
maxLen = max(maxLen, i - prefIdx[prefSum - target])
# Store prefix sum with its index
if prefSum not in prefIdx:
prefIdx[prefSum] = i
return -1 if maxLen == -1 else len(arr) - maxLen
if __name__ == "__main__":
arr = [3, 4, 1, 3, 2]
k = 5
print(minRemovals(arr, k))
using System;
using System.Collections.Generic;
class GfG {
static int minRemovals(int[] arr, int k) {
int total = 0;
foreach (int num in arr)
total += num;
if (k == total)
return arr.Length;
// Find the target sum for the longest subarray
int target = total - k;
Dictionary<int, int> prefIdx = new Dictionary<int, int>();
int prefSum = 0, maxLen = -1;
for (int i = 0; i < arr.Length; i++) {
prefSum += arr[i];
if (prefSum == target)
maxLen = i + 1;
else if (prefIdx.ContainsKey(prefSum - target))
maxLen = Math.Max(maxLen, i - prefIdx[prefSum - target]);
// Store prefix sum with its index
if (!prefIdx.ContainsKey(prefSum))
prefIdx[prefSum] = i;
}
return maxLen == -1 ? -1 : arr.Length - maxLen;
}
static void Main() {
int[] arr = { 3, 4, 1, 3, 2 };
int k = 5;
Console.WriteLine(minRemovals(arr, k));
}
}
function minRemovals(arr, k) {
let total = 0;
for (let num of arr)
total += num;
if (k === total)
return arr.length;
// Find the target sum for the longest subarray
let target = total - k;
let prefIdx = new Map();
let prefSum = 0, maxLen = -1;
for (let i = 0; i < arr.length; i++) {
prefSum += arr[i];
if (prefSum === target)
maxLen = i + 1;
else if (prefIdx.has(prefSum - target))
maxLen = Math.max(maxLen, i - prefIdx.get(prefSum - target));
// Store prefix sum with its index
if (!prefIdx.has(prefSum))
prefIdx.set(prefSum, i);
}
return maxLen === -1 ? -1 : arr.length - maxLen;
}
// Driver Code
const arr = [3, 4, 1, 3, 2];
const k = 5;
console.log(minRemovals(arr, k));
Output
2
[Expected Approach] Using Sliding Window Technique - O(n) Time and O(1) Space
In the previous approach, we observed that in order to find the minimum removals with sum k, we need to find the longest subarray with sum (total sum - k). Since the input array contains only positive numbers, we can further optimize our previous approach by using Sliding Window Technique to find the longest subarray having sum = (total sum - k).
- Start with a window of size 1 having only the first element.
- Extend the window until the sum of elements exceeds (total sum - k).
- Shrink the window from the left until sum of elements <= (total sum - k).
- If sum of elements
== (total sum - k), find the length of window (right - left + 1) and update the maximum length.Finally, minimum removals = n - maximum length of window having sum as (total sum - k).
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
int minRemovals(vector<int> &arr, int k) {
int total = 0, n = arr.size();
for (int num : arr)
total += num;
int target = total - k;
// If target sum = 0, all elements must be removed
if (target == 0)
return n;
int left = 0, currSum = 0, maxLen = -1;
// Use the sliding window technique
for (int right = 0; right < n; right++) {
currSum += arr[right];
// Shrink the window from the left if the
// current sum exceeds the required sum
while (left < right && currSum > target) {
currSum -= arr[left++];
}
if (currSum == target) {
maxLen = max(maxLen, right - left + 1);
}
}
// If no valid subarray is found, return -1;
// otherwise, return the minimum removals
return maxLen == -1 ? -1 : n - maxLen;
}
int main() {
vector<int> arr = {3, 4, 1, 3, 2};
int k = 5;
cout << minRemovals(arr, k) << endl;
return 0;
}
class GfG {
static int minRemovals(int[] arr, int k) {
int total = 0, n = arr.length;
for (int num : arr)
total += num;
int target = total - k;
// If target sum = 0, all elements must be removed
if (target == 0)
return n;
int left = 0, currSum = 0, maxLen = -1;
// Use the sliding window technique
for (int right = 0; right < n; right++) {
currSum += arr[right];
// Shrink the window from the left if the
// current sum exceeds the required sum
while (left < right && currSum > target) {
currSum -= arr[left++];
}
if (currSum == target) {
maxLen = Math.max(maxLen, right - left + 1);
}
}
// If no valid subarray is found, return -1;
// otherwise, return the minimum removals
return maxLen == -1 ? -1 : n - maxLen;
}
public static void main(String[] args) {
int[] arr = {3, 4, 1, 3, 2};
int k = 5;
System.out.println(minRemovals(arr, k));
}
}
def minRemovals(arr, k):
total = 0
n = len(arr)
for num in arr:
total += num
target = total - k
# If target sum = 0, all elements must be removed
if target == 0:
return n
left = 0
currSum = 0
maxLen = -1
# Use the sliding window technique
for right in range(n):
currSum += arr[right]
# Shrink the window from the left if the
# current sum exceeds the required sum
while left < right and currSum > target:
currSum -= arr[left]
left += 1
if currSum == target:
maxLen = max(maxLen, right - left + 1)
# If no valid subarray is found, return -1;
# otherwise, return the minimum removals
return -1 if maxLen == -1 else n - maxLen
if __name__ == "__main__":
arr = [3, 4, 1, 3, 2]
k = 5
print(minRemovals(arr, k))
using System;
class GfG {
static int minRemovals(int[] arr, int k) {
int total = 0, n = arr.Length;
foreach (int num in arr)
total += num;
int target = total - k;
// If target sum = 0, all elements must be removed
if (target == 0)
return n;
int left = 0, currSum = 0, maxLen = -1;
// Use the sliding window technique
for (int right = 0; right < n; right++) {
currSum += arr[right];
// Shrink the window from the left if the
// current sum exceeds the required sum
while (left < right && currSum > target) {
currSum -= arr[left++];
}
if (currSum == target) {
maxLen = Math.Max(maxLen, right - left + 1);
}
}
// If no valid subarray is found, return -1;
// otherwise, return the minimum removals
return maxLen == -1 ? -1 : n - maxLen;
}
static void Main() {
int[] arr = new int[] { 3, 4, 1, 3, 2 };
int k = 5;
Console.WriteLine(minRemovals(arr, k));
}
}
function minRemovals(arr, k) {
let total = 0, n = arr.length;
for (let num of arr) {
total += num;
}
let target = total - k;
// If target sum = 0, all elements must be removed
if (target === 0) {
return n;
}
let left = 0, currSum = 0, maxLen = -1;
// Use the sliding window technique
for (let right = 0; right < n; right++) {
currSum += arr[right];
// Shrink the window from the left if the
// current sum exceeds the required sum
while (left < right && currSum > target) {
currSum -= arr[left++];
}
if (currSum === target) {
maxLen = Math.max(maxLen, right - left + 1);
}
}
// If no valid subarray is found, return -1;
// otherwise, return the minimum removals
return maxLen === -1 ? -1 : n - maxLen;
}
// Driver Code
const arr = [3, 4, 1, 3, 2];
const k = 5;
console.log(minRemovals(arr, k));
Output
2