Given an array arr[] of size N and an integer K, the task is to find the length of the longest subarray consisting of same elements that can be obtained by decrementing the array elements by 1 at most K times.
Example:
Input: arr[] = { 1, 2, 3 }, K = 1
Output: 2
Explanation:
Decrementing arr[0] by 1 modifies arr[] to { 1, 1, 3 }
The longest subarray with equal elements is { 1, 1 }.
Therefore, the required output is 2.Input: arr[] = { 1, 7, 3, 4, 5, 6 }, K = 6
Output: 4
Approach: The problem can be solved using Segment tree and Binary Search technique. The idea is to use the following observations:
Total number of decrements operations required to make all array elements of the subarray { arr[start], …, arr[end] } equal
= (?(start, end)) – (end – start + 1) * (min_value)where, start = index of the starting point of the subarray
end = index of end point of subarray
min_value = smallest value from index i to j
?(start, end) = sum of all elements from index i to j
Follow the steps below to solve the above problem:
- Initialize a segment tree to calculate the smallest element in a subarray of the array and a prefix sum array to calculate the sum elements of a subarray.
-
Traverse the array, arr[]. For every ith element perform the following operations:
- Initialize two variables say, start = i, end = N – 1 and apply binary search over the range [start, end] to check if the all the elements of the subarray { arr[start], …, arr[end] } can be made equal or not by decrementing at most K operations from the above observations.
- If all the elements of the subarray { arr[start], …, arr[end] } can be made equal by decrementing at most K operations then update start = (start + end) / 2 + 1.
- Otherwise, update end = (start + end) / 2 – 1
- Finally, print the length of the longest subarray obtained from the above operations.
Below is the implementation of the above approach:
// C++ program to implement // the above approach #include <bits/stdc++.h> using namespace std;
// Function to construct Segment Tree // to return the minimum element in a range int build( int tree[], int * A, int start,
int end, int node)
{ // If leaf nodes of
// the tree are found
if (start == end) {
// Update the value in segment
// tree from given array
tree[node] = A[start];
return tree[node];
}
// Divide left and right subtree
int mid = (start + end) / 2;
// Stores smallest element in
// subarray { arr[start], arr[mid] }
int X = build(tree, A, start, mid,
2 * node + 1);
// Stores smallest element in
// subarray { arr[mid + 1], arr[end] }
int Y = build(tree, A, mid + 1,
end, 2 * node + 2);
// Stores smallest element in
// subarray { arr[start], arr[end] }
return tree[node] = min(X, Y);
} // Function to find the smallest // element present in a subarray int query( int tree[], int start, int end,
int l, int r, int node)
{ // If elements of the subarray
// are not in the range [l, r]
if (start > r || end < l)
return INT_MAX;
// If all the elements of the
// subarray are in the range [l, r]
if (start >= l && end <= r)
return tree[node];
// Divide tree into left
// and right subtree
int mid = (start + end) / 2;
// Stores smallest element
// in left subtree
int X = query(tree, start, mid, l,
r, 2 * node + 1);
// Stores smallest element in
// right subtree
int Y = query(tree, mid + 1, end, l,
r, 2 * node + 2);
return min(X, Y);
} // Function that find length of longest // subarray with all equal elements in // atmost K decrements int longestSubArray( int * A, int N, int K)
{ // Stores length of longest subarray
// with all equal elements in atmost
// K decrements.
int res = 1;
// Store the prefix sum array
int preSum[N + 1];
// Calculate the prefix sum array
preSum[0] = A[0];
for ( int i = 0; i < N; i++)
preSum[i + 1] = preSum[i] + A[i];
int tree[4 * N + 5];
// Build the segment tree
// for range min query
build(tree, A, 0, N - 1, 0);
// Traverse the array
for ( int i = 0; i < N; i++) {
// Stores start index
// of the subarray
int start = i;
// Stores end index
// of the subarray
int end = N - 1;
int mid;
// Stores end index of
// the longest subarray
int max_index = i;
// Performing the binary search
// to find the endpoint
// for the selected range
while (start <= end) {
// Find the mid for binary search
mid = (start + end) / 2;
// Find the smallest element in
// range [i, mid] using Segment Tree
int min_element
= query(tree, 0, N - 1, i, mid, 0);
// Stores total sum of subarray
// after K decrements
int expected_sum
= (mid - i + 1) * min_element;
// Stores sum of elements of
// subarray before K decrements
int actual_sum
= preSum[mid + 1] - preSum[i];
// If subarray found with
// all equal elements
if (actual_sum - expected_sum <= K) {
// Update start
start = mid + 1;
// Update max_index
max_index = max(max_index, mid);
}
// If false, it means that
// the selected range is invalid
else {
// Update end
end = mid - 1;
}
}
// Store the length of longest subarray
res = max(res, max_index - i + 1);
}
// Return result
return res;
} // Driver Code int main()
{ int arr[] = { 1, 7, 3, 4, 5, 6 };
int k = 6;
int n = 6;
cout << longestSubArray(arr, n, k);
return 0;
} |
// Java program to implement // the above approach import java.util.*;
class GFG{
// Function to construct Segment Tree // to return the minimum element in a range static int build( int tree[], int [] A, int start,
int end, int node)
{ // If leaf nodes of
// the tree are found
if (start == end)
{
// Update the value in segment
// tree from given array
tree[node] = A[start];
return tree[node];
}
// Divide left and right subtree
int mid = (start + end) / 2 ;
// Stores smallest element in
// subarray { arr[start], arr[mid] }
int X = build(tree, A, start, mid,
2 * node + 1 );
// Stores smallest element in
// subarray { arr[mid + 1], arr[end] }
int Y = build(tree, A, mid + 1 ,
end, 2 * node + 2 );
// Stores smallest element in
// subarray { arr[start], arr[end] }
return (tree[node] = Math.min(X, Y));
} // Function to find the smallest // element present in a subarray static int query( int tree[], int start, int end,
int l, int r, int node)
{ // If elements of the subarray
// are not in the range [l, r]
if (start > r || end < l)
return Integer.MAX_VALUE;
// If all the elements of the
// subarray are in the range [l, r]
if (start >= l && end <= r)
return tree[node];
// Divide tree into left
// and right subtree
int mid = (start + end) / 2 ;
// Stores smallest element
// in left subtree
int X = query(tree, start, mid, l,
r, 2 * node + 1 );
// Stores smallest element in
// right subtree
int Y = query(tree, mid + 1 , end, l,
r, 2 * node + 2 );
return Math.min(X, Y);
} // Function that find length of longest // subarray with all equal elements in // atmost K decrements static int longestSubArray( int [] A, int N, int K)
{ // Stores length of longest subarray
// with all equal elements in atmost
// K decrements.
int res = 1 ;
// Store the prefix sum array
int preSum[] = new int [N + 1 ];
// Calculate the prefix sum array
preSum[ 0 ] = A[ 0 ];
for ( int i = 0 ; i < N; i++)
preSum[i + 1 ] = preSum[i] + A[i];
int tree[] = new int [ 4 * N + 5 ];
// Build the segment tree
// for range min query
build(tree, A, 0 , N - 1 , 0 );
// Traverse the array
for ( int i = 0 ; i < N; i++)
{
// Stores start index
// of the subarray
int start = i;
// Stores end index
// of the subarray
int end = N - 1 ;
int mid;
// Stores end index of
// the longest subarray
int max_index = i;
// Performing the binary search
// to find the endpoint
// for the selected range
while (start <= end)
{
// Find the mid for binary search
mid = (start + end) / 2 ;
// Find the smallest element in
// range [i, mid] using Segment Tree
int min_element = query(tree, 0 , N - 1 ,
i, mid, 0 );
// Stores total sum of subarray
// after K decrements
int expected_sum = (mid - i + 1 ) *
min_element;
// Stores sum of elements of
// subarray before K decrements
int actual_sum = preSum[mid + 1 ] -
preSum[i];
// If subarray found with
// all equal elements
if (actual_sum - expected_sum <= K)
{
// Update start
start = mid + 1 ;
// Update max_index
max_index = Math.max(max_index, mid);
}
// If false, it means that
// the selected range is invalid
else {
// Update end
end = mid - 1 ;
}
}
// Store the length of longest subarray
res = Math.max(res, max_index - i + 1 );
}
// Return result
return res;
} // Driver Code static public void main(String args[])
{ int arr[] = { 1 , 7 , 3 , 4 , 5 , 6 };
int k = 6 ;
int n = 6 ;
System.out.print(longestSubArray(arr, n, k));
} } // This code is contributed by sanjoy_62 |
# Python3 program to implement # the above approach import sys
# Function to construct Segment Tree # to return the minimum element in a range def build(tree, A, start, end, node):
# If leaf nodes of
# the tree are found
if (start = = end):
# Update the value in segment
# tree from given array
tree[node] = A[start]
return tree[node]
# Divide left and right subtree
mid = ( int )((start + end) / 2 )
# Stores smallest element in
# subarray : arr[start], arr[mid]
X = build(tree, A, start, mid,
2 * node + 1 )
# Stores smallest element in
# subarray : arr[mid + 1], arr[end]
Y = build(tree, A, mid + 1 ,
end, 2 * node + 2 )
# Stores smallest element in
# subarray : arr[start], arr[end]
return (tree[node] = = min (X, Y))
# Function to find the smallest # element present in a subarray def query(tree, start, end, l, r, node):
# If elements of the subarray
# are not in the range [l, r]
if (start > r or end < l) :
return sys.maxsize
# If all the elements of the
# subarray are in the range [l, r]
if (start > = l and end < = r):
return tree[node]
# Divide tree into left
# and right subtree
mid = ( int )((start + end) / 2 )
# Stores smallest element
# in left subtree
X = query(tree, start, mid, l,
r, 2 * node + 1 )
# Stores smallest element in
# right subtree
Y = query(tree, mid + 1 , end, l,
r, 2 * node + 2 )
return min (X, Y)
# Function that find length of longest # subarray with all equal elements in # atmost K decrements def longestSubArray(A, N, K):
# Stores length of longest subarray
# with all equal elements in atmost
# K decrements.
res = 1
# Store the prefix sum array
preSum = [ 0 ] * (N + 1 )
# Calculate the prefix sum array
preSum[ 0 ] = A[ 0 ]
for i in range (N):
preSum[i + 1 ] = preSum[i] + A[i]
tree = [ 0 ] * ( 4 * N + 5 )
# Build the segment tree
# for range min query
build(tree, A, 0 , N - 1 , 0 )
# Traverse the array
for i in range (N):
# Stores start index
# of the subarray
start = i
# Stores end index
# of the subarray
end = N - 1
# Stores end index of
# the longest subarray
max_index = i
# Performing the binary search
# to find the endpoint
# for the selected range
while (start < = end):
# Find the mid for binary search
mid = ( int )((start + end) / 2 )
# Find the smallest element in
# range [i, mid] using Segment Tree
min_element = query(tree, 0 , N - 1 , i, mid, 0 )
# Stores total sum of subarray
# after K decrements
expected_sum = (mid - i + 1 ) * min_element
# Stores sum of elements of
# subarray before K decrements
actual_sum = preSum[mid + 1 ] - preSum[i]
# If subarray found with
# all equal elements
if (actual_sum - expected_sum < = K):
# Update start
start = mid + 1
# Update max_index
max_index = max (max_index, mid)
# If false, it means that
# the selected range is invalid
else :
# Update end
end = mid - 1
# Store the length of longest subarray
res = max (res, max_index - i + 2 )
# Return result
return res
# Driver Code arr = [ 1 , 7 , 3 , 4 , 5 , 6 ]
k = 6
n = 6
print (longestSubArray(arr, n, k))
# This code is contributed by splevel62 |
// C# program to implement // the above approach using System;
class GFG{
// Function to construct Segment Tree // to return the minimum element in a range static int build( int [] tree, int [] A, int start,
int end, int node)
{ // If leaf nodes of
// the tree are found
if (start == end)
{
// Update the value in segment
// tree from given array
tree[node] = A[start];
return tree[node];
}
// Divide left and right subtree
int mid = (start + end) / 2;
// Stores smallest element in
// subarray { arr[start], arr[mid] }
int X = build(tree, A, start, mid,
2 * node + 1);
// Stores smallest element in
// subarray { arr[mid + 1], arr[end] }
int Y = build(tree, A, mid + 1,
end, 2 * node + 2);
// Stores smallest element in
// subarray { arr[start], arr[end] }
return (tree[node] = Math.Min(X, Y));
} // Function to find the smallest // element present in a subarray static int query( int [] tree, int start, int end,
int l, int r, int node)
{ // If elements of the subarray
// are not in the range [l, r]
if (start > r || end < l)
return Int32.MaxValue;
// If all the elements of the
// subarray are in the range [l, r]
if (start >= l && end <= r)
return tree[node];
// Divide tree into left
// and right subtree
int mid = (start + end) / 2;
// Stores smallest element
// in left subtree
int X = query(tree, start, mid, l,
r, 2 * node + 1);
// Stores smallest element in
// right subtree
int Y = query(tree, mid + 1, end, l,
r, 2 * node + 2);
return Math.Min(X, Y);
} // Function that find length of longest // subarray with all equal elements in // atmost K decrements static int longestSubArray( int [] A, int N, int K)
{ // Stores length of longest subarray
// with all equal elements in atmost
// K decrements.
int res = 1;
// Store the prefix sum array
int [] preSum = new int [N + 1];
// Calculate the prefix sum array
preSum[0] = A[0];
for ( int i = 0; i < N; i++)
preSum[i + 1] = preSum[i] + A[i];
int [] tree = new int [4 * N + 5];
// Build the segment tree
// for range min query
build(tree, A, 0, N - 1, 0);
// Traverse the array
for ( int i = 0; i < N; i++)
{
// Stores start index
// of the subarray
int start = i;
// Stores end index
// of the subarray
int end = N - 1;
int mid;
// Stores end index of
// the longest subarray
int max_index = i;
// Performing the binary search
// to find the endpoint
// for the selected range
while (start <= end)
{
// Find the mid for binary search
mid = (start + end) / 2;
// Find the smallest element in
// range [i, mid] using Segment Tree
int min_element = query(tree, 0, N - 1,
i, mid, 0);
// Stores total sum of subarray
// after K decrements
int expected_sum = (mid - i + 1) *
min_element;
// Stores sum of elements of
// subarray before K decrements
int actual_sum = preSum[mid + 1] -
preSum[i];
// If subarray found with
// all equal elements
if (actual_sum - expected_sum <= K)
{
// Update start
start = mid + 1;
// Update max_index
max_index = Math.Max(max_index, mid);
}
// If false, it means that
// the selected range is invalid
else
{
// Update end
end = mid - 1;
}
}
// Store the length of longest subarray
res = Math.Max(res, max_index - i + 1);
}
// Return result
return res;
} // Driver Code static void Main()
{ int [] arr = { 1, 7, 3, 4, 5, 6 };
int k = 6;
int n = 6;
Console.WriteLine(longestSubArray(arr, n, k));
} } // This code is contributed by susmitakundugoaldanga |
<script> // JavaScript program to implement // the above approach // Function to construct Segment Tree // to return the minimum element in a range function build(tree,A, start,end, node)
{ // If leaf nodes of
// the tree are found
if (start == end) {
// Update the value in segment
// tree from given array
tree[node] = A[start];
return tree[node];
}
// Divide left and right subtree
let mid = Math.floor((start + end) / 2);
// Stores smallest element in
// subarray { arr[start], arr[mid] }
let X = build(tree, A, start, mid,
2 * node + 1);
// Stores smallest element in
// subarray { arr[mid + 1], arr[end] }
let Y = build(tree, A, mid + 1,
end, 2 * node + 2);
// Stores smallest element in
// subarray { arr[start], arr[end] }
return tree[node] = Math.min(X, Y);
} // Function to find the smallest // element present in a subarray function query(tree,start, end,l, r, node)
{ // If elements of the subarray
// are not in the range [l, r]
if (start > r || end < l)
return Number.MAX_VALUE;
// If all the elements of the
// subarray are in the range [l, r]
if (start >= l && end <= r)
return tree[node];
// Divide tree into left
// and right subtree
let mid = Math.floor((start + end) / 2);
// Stores smallest element
// in left subtree
let X = query(tree, start, mid, l,
r, 2 * node + 1);
// Stores smallest element in
// right subtree
let Y = query(tree, mid + 1, end, l,
r, 2 * node + 2);
return Math.min(X, Y);
} // Function that find length of longest // subarray with all equal elements in // atmost K decrements function longestSubArray(A,N,K)
{ // Stores length of longest subarray
// with all equal elements in atmost
// K decrements.
let res = 1;
// Store the prefix sum array
let preSum = new Array(N + 1);
// Calculate the prefix sum array
preSum[0] = A[0];
for (let i = 0; i < N; i++)
preSum[i + 1] = preSum[i] + A[i];
let tree = new Array(4 * N + 5);
// Build the segment tree
// for range min query
build(tree, A, 0, N - 1, 0);
// Traverse the array
for (let i = 0; i < N; i++) {
// Stores start index
// of the subarray
let start = i;
// Stores end index
// of the subarray
let end = N - 1;
let mid;
// Stores end index of
// the longest subarray
let max_index = i;
// Performing the binary search
// to find the endpoint
// for the selected range
while (start <= end) {
// Find the mid for binary search
mid = Math.floor((start + end) / 2);
// Find the smallest element in
// range [i, mid] using Segment Tree
let min_element
= query(tree, 0, N - 1, i, mid, 0);
// Stores total sum of subarray
// after K decrements
let expected_sum
= (mid - i + 1) * min_element;
// Stores sum of elements of
// subarray before K decrements
let actual_sum
= preSum[mid + 1] - preSum[i];
// If subarray found with
// all equal elements
if (actual_sum - expected_sum <= K) {
// Update start
start = mid + 1;
// Update max_index
max_index = Math.max(max_index, mid);
}
// If false, it means that
// the selected range is invalid
else {
// Update end
end = mid - 1;
}
}
// Store the length of longest subarray
res = Math.max(res, max_index - i + 1);
}
// Return result
return res;
} // Driver Code let arr = [ 1, 7, 3, 4, 5, 6 ]; let k = 6; let n = 6; document.write(longestSubArray(arr, n, k), "</br>" );
// This code is contributed by shinjanpatra </script> |
4
Time Complexity: O(N * (log(N))2)
Auxiliary Space: O(N)
Related Topic: Segment Tree