Open In App

Divide a sorted array in K parts with sum of difference of max and min minimized in each part - Set 2

Last Updated : 18 Jan, 2022
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an ascending sorted array arr[] of size N and an integer K, the task is to partition the given array into K non-empty subarrays such that the sum of differences of the maximum and the minimum of each subarray is minimized.

Examples:

Input: arr[] = { 10, 20, 70, 80 },  N = 4, K = 2
Output: 20
Explanation: The given array can be split in the following way
{10, 20} and {70, 80}. The differences are (20 - 10) = 10 and (80 - 70) = 10
The sum = 10 + 10 = 20

Input:  arr[] = { 5, 10, 50, 70 }, N = 4, K = 3
Output: 5
Explanation: The subarrays are {5, 10}, {50}, {70}
The differences are 10 - 5 = 5, 50 - 50 = 0, 70 - 70 = 0
The sum = 5 + 0 + 0 = 5

 

Approach: The other approaches are discussed in Set 1 of this article. Here, we are discussing the Binary Search approach.

Space Optimized Approach: The idea is to use binary search in order to find the answer. The answer lies in [ 0, ( arr[N-1] - arr[0]) ]. See the following observation for justification.

  • Assuming permission to make as many cuts as possible, the answer would be 0 because each element can form a subarray. Thus the minimum value would be 0.
  • Now the other extreme case can be when only one subarray is allowed, In this case, the answer would be (arr[N-1] - arr[0]). These were the two extreme cases and it is guaranteed that the answer would lie in between them.

 Follow the steps below to solve the problem:

  • Initialize the variable ans as 0 to store the answer.
  • Apply binary search with low = 0, and high = arr[N-1] - arr[0].
  • For each value of mid, check if a tape of length mid can cover all the holes within K cuts.
  • If so then we have arrived at a potential answer. Store the value and check if it is possible to do the same for a smaller length of tape. (make high = mid - 1 )
  • If not then find a larger value for mid (low = mid + 1).

Below is the implementation of the above approach.

C++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;

bool isValid(vector<int> arr, int max_cuts, int len)
{

    // Max_cuts is the maximum no. of
    // allowed cuts.
    int n = arr.size();
    int start = 0;
    int i = 1;
    while (i < n) {

        // Start from covering as many holes
        // as you can from start.
        if (arr[i] - arr[start] <= len) {
            i++;
        }
        else {

            // If an index is reached
            // from where it's not possible
            // to accommodate more elements
            // in the current subarray
            // then end this subarray
            // and go further.
            len = len - (arr[i - 1] - arr[start]);
            max_cuts--;
            start = i;
            i++;
        }

        // If at any point you run out
        // of maximum subarrays or length
        // then return false because it's
        // impossible to obtain this
        // value of mid.
        if (max_cuts <= 0 || len <= 0)
            return false;
    }

    // Covered all subarrays within
    // the sum maximum number of subarrays
    // so return true.
    return true;
}

// Function to find the minimum sum
void findMinTapeLength(vector<int> arr, int N, int K)
{
    // Initialise low and high
    int high = arr[N - 1] - arr[0], low = 0;
    int ans = 0;

    // Apply Binary Search
    while (low <= high) {
        int mid = low + (high - low) / 2;

        // IsValid() function checks if
        // max value of mid is sufficient
        // to break the array in K subarrays
        if (isValid(arr, K, mid)) {

            // If true then set this as
            // the current answer and divide
            // your range to [low, mid-1]
            // to check for a lower sum
            ans = mid;
            high = mid - 1;
        }
        // If false then that means need
        // to increase the current length
        // so set range to [mid+1, high]
        else
            low = mid + 1;
    }
    cout << ans;
}

// Driver Code
int main()
{
    vector<int> arr = { 10, 20, 70, 80 };
    int N = 4, K = 2;
    findMinTapeLength(arr, N, K);
}

// This code is contributed by Samim Hossain Mondal.
Java
// Java program for the above approach
import java.io.*;

class GFG {

    // Function to find the minimum sum
    static void findMinTapeLength(int[] arr, 
                                  int N, int K)
    {
        // Initialise low and high
        int high = arr[N - 1] - arr[0], low = 0;
        int ans = 0;

        // Apply Binary Search
        while (low <= high) {
            int mid = low + (high - low) / 2;

            // IsValid() function checks if
            // max value of mid is sufficient 
            // to break the array in K subarrays
            if (isValid(arr, K, mid)) {

                // If true then set this as 
                // the current answer and divide 
                // your range to [low, mid-1] 
                // to check for a lower sum
                ans = mid;
                high = mid - 1;
            }
            // If false then that means need 
            // to increase the current length 
            // so set range to [mid+1, high]
            else
                low = mid + 1;
        }
        System.out.println(ans);
    }

    static boolean isValid(int[] arr, 
                           int max_cuts, 
                           int len)
    {

        // Max_cuts is the maximum no. of 
        // allowed cuts.
        int n = arr.length;
        int start = 0;
        int i = 1;
        while (i < n) {

            // Start from covering as many holes
            // as you can from start.
            if (arr[i] - arr[start] <= 
                len) {
                i++;
            }
            else {

                // If an index is reached 
                // from where it's not possible 
                // to accommodate more elements
                // in the current subarray 
                // then end this subarray 
                // and go further.
                len = len - (arr[i - 1] - 
                             arr[start]);
                max_cuts--;
                start = i;
                i++;
            }

            // If at any point you run out 
            // of maximum subarrays or length 
            // then return false because it's
            // impossible to obtain this 
            // value of mid.
            if (max_cuts <= 0 || len <= 0)
                return false;
        }

        // Covered all subarrays within
        // the sum maximum number of subarrays
        // so return true.
        return true;
    }

    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 10, 20, 70, 80 };
        int N = 4, K = 2;
        findMinTapeLength(arr, N, K);
    }
}
Python3
# Python code for the above approach

# Function to find the minimum sum
def findMinTapeLength(arr, N, K):

    # Initialise low and high
    high = arr[N - 1] - arr[0]
    low = 0
    ans = 0

    # Apply Binary Search
    while (low <= high):
        mid = low + ((high - low) // 2)

        # IsValid() function checks if
        # max value of mid is sufficient
        # to break the array in K subarrays
        if (isValid(arr, K, mid)):

            # If true then set this as
            # the current answer and divide
            # your range to [low, mid-1]
            # to check for a lower sum
            ans = mid
            high = mid - 1

        # If false then that means need
        # to increase the current length
        # so set range to [mid+1, high]
        else:
            low = mid + 1
    print(ans)


def isValid(arr, max_cuts, _len):

    # Max_cuts is the maximum no. of
    # allowed cuts.
    n = len(arr)
    start = 0
    i = 1
    while (i < n):

        # Start from covering as many holes
        # as you can from start.
        if (arr[i] - arr[start] <= _len):
            i += 1
        else:

            # If an index is reached
            # from where it's not possible
            # to accommodate more elements
            # in the current subarray
            # then end this subarray
            # and go further.
            _len = _len - (arr[i - 1] - arr[start])
            max_cuts -= 1
            start = i
            i += 1

        # If at any point you run out
        # of maximum subarrays or length
        # then return false because it's
        # impossible to obtain this
        # value of mid.
        if (max_cuts <= 0 or _len <= 0):
            return False

    # Covered all subarrays within
    # the sum maximum number of subarrays
    # so return true.
    return True


# Driver Code
arr = [10, 20, 70, 80]
N = 4
K = 2
findMinTapeLength(arr, N, K)

# This code is contributed by gfgking
C#
// C# program for the above approach
using System;
class GFG {

  // Function to find the minimum sum
  static void findMinTapeLength(int[] arr, 
                                int N, int K)
  {

    // Initialise low and high
    int high = arr[N - 1] - arr[0], low = 0;
    int ans = 0;

    // Apply Binary Search
    while (low <= high) {
      int mid = low + (high - low) / 2;

      // IsValid() function checks if
      // max value of mid is sufficient 
      // to break the array in K subarrays
      if (isValid(arr, K, mid)) {

        // If true then set this as 
        // the current answer and divide 
        // your range to [low, mid-1] 
        // to check for a lower sum
        ans = mid;
        high = mid - 1;
      }

      // If false then that means need 
      // to increase the current length 
      // so set range to [mid+1, high]
      else
        low = mid + 1;
    }
    Console.WriteLine(ans);
  }

  static bool isValid(int[] arr, 
                      int max_cuts, 
                      int len)
  {

    // Max_cuts is the maximum no. of 
    // allowed cuts.
    int n = arr.Length;
    int start = 0;
    int i = 1;
    while (i < n) {

      // Start from covering as many holes
      // as you can from start.
      if (arr[i] - arr[start] <= 
          len) {
        i++;
      }
      else {

        // If an index is reached 
        // from where it's not possible 
        // to accommodate more elements
        // in the current subarray 
        // then end this subarray 
        // and go further.
        len = len - (arr[i - 1] - 
                     arr[start]);
        max_cuts--;
        start = i;
        i++;
      }

      // If at any point you run out 
      // of maximum subarrays or length 
      // then return false because it's
      // impossible to obtain this 
      // value of mid.
      if (max_cuts <= 0 || len <= 0)
        return false;
    }

    // Covered all subarrays within
    // the sum maximum number of subarrays
    // so return true.
    return true;
  }

  // Driver Code
  public static void Main()
  {
    int[] arr = { 10, 20, 70, 80 };
    int N = 4, K = 2;
    findMinTapeLength(arr, N, K);
  }
}

// This code is contributed by Samim Hossain Mondal.
JavaScript
  <script>
        // JavaScript code for the above approach

        // Function to find the minimum sum
        function findMinTapeLength(arr,
            N, K)
        {
        
            // Initialise low and high
            let high = arr[N - 1] - arr[0], low = 0;
            let ans = 0;

            // Apply Binary Search
            while (low <= high)
            {
                let mid = low + Math.floor((high - low) / 2);

                // IsValid() function checks if
                // max value of mid is sufficient 
                // to break the array in K subarrays
                if (isValid(arr, K, mid)) {

                    // If true then set this as 
                    // the current answer and divide 
                    // your range to [low, mid-1] 
                    // to check for a lower sum
                    ans = mid;
                    high = mid - 1;
                }
                
                // If false then that means need 
                // to increase the current length 
                // so set range to [mid+1, high]
                else
                    low = mid + 1;
            }
            document.write(ans);
        }

        function isValid(arr, max_cuts, len) 
        {

            // Max_cuts is the maximum no. of 
            // allowed cuts.
            let n = arr.length;
            let start = 0;
            let i = 1;
            while (i < n) {

                // Start from covering as many holes
                // as you can from start.
                if (arr[i] - arr[start] <=
                    len) {
                    i++;
                }
                else {

                    // If an index is reached 
                    // from where it's not possible 
                    // to accommodate more elements
                    // in the current subarray 
                    // then end this subarray 
                    // and go further.
                    len = len - (arr[i - 1] -
                        arr[start]);
                    max_cuts--;
                    start = i;
                    i++;
                }

                // If at any point you run out 
                // of maximum subarrays or length 
                // then return false because it's
                // impossible to obtain this 
                // value of mid.
                if (max_cuts <= 0 || len <= 0)
                    return false;
            }

            // Covered all subarrays within
            // the sum maximum number of subarrays
            // so return true.
            return true;
        }

        // Driver Code
        let arr = [10, 20, 70, 80];
        let N = 4, K = 2;
        findMinTapeLength(arr, N, K);

  // This code is contributed by Potta Lokesh
    </script>

Output
20

Time Complexity: O(N*log(M)), where M is the maximum value of the array.
Auxiliary Space: O(1)


 


Next Article

Similar Reads