Skip to content
Related Articles

Related Articles

Improve Article

Maximize length of longest subarray consisting of same elements by at most K decrements

  • Last Updated : 19 Jul, 2021

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:

  1. 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.
  2. 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
       
  3. Finally, print the length of the longest subarray obtained from the above operations.

Below is the implementation of the above approach:

C++




// 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




// 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




# 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#




// 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
Output:
4

 

Time Complexity: O(N * (log(N))2)
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :