将排序后的数组划分为 K 个部分,每个部分的最大和最小差之和最小化 – 集 2
给定一个大小为N的升序排序数组arr[]和一个整数K ,任务是将给定数组划分为K个非空子数组,以使每个子数组的最大值和最小值的差之和最小化。
例子:
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
方法:本文的第 1 组讨论了其他方法。在这里,我们正在讨论二分搜索方法。
空间优化方法:这个想法是使用 二进制搜索以找到答案。答案在于 [ 0, ( arr[N-1] – arr[0]) ]。请参阅以下观察说明。
- 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.
请按照以下步骤解决问题:
- 将变量ans初始化为0以存储答案。
- 使用low = 0和high = 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)