📌  相关文章
📜  将排序后的数组划分为 K 个部分,每个部分的最大和最小差之和最小化 – 集 2

📅  最后修改于: 2022-05-13 01:56:08.059000             🧑  作者: Mango

将排序后的数组划分为 K 个部分,每个部分的最大和最小差之和最小化 – 集 2

给定一个大小为N的升序排序数组arr[]和一个整数K ,任务是将给定数组划分为K个非空子数组,以使每个子数组的最大值和最小值的差之和最小化。

例子:

方法:本文的第 1 组讨论了其他方法。在这里,我们正在讨论二分搜索方法。

空间优化方法:这个想法是使用 二进制搜索以找到答案。答案在于 [ 0, ( arr[N-1] – arr[0]) ]。请参阅以下观察说明。

请按照以下步骤解决问题:

  • 将变量ans初始化为0以存储答案。
  • 使用low = 0high = arr[N-1] – arr[0]应用二分搜索。
  • 对于mid的每个值,检查长度为 mid 的胶带是否可以覆盖K个切口内的所有孔。
  • 如果是这样,那么我们已经得出了一个潜在的答案。存储该值并检查是否可以对较小长度的磁带执行相同操作。 (使高=中 - 1
  • 如果不是,则为 mid ( low = mid + 1 ) 找到更大的值。

下面是上述方法的实现。

C++
// C++ program for the above approach
#include 
using namespace std;
 
bool isValid(vector 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 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 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


输出
20

时间复杂度: O(N*log(M)),其中 M 是数组的最大值。
辅助空间: O(1)