问题描述 链接到标题
2517. 礼盒的最大甜蜜度 (Medium)
给你一个正整数数组 price
,其中 price[i]
表示第 i
类糖
果的价格,另给你一个正整数 k
。
商店组合 k
类 不同 糖果打包成礼盒出售。礼盒的 **甜蜜度
** 是礼盒中任意两种糖果 价格 绝对差的最小值。
返回礼盒的 最大 甜蜜度。
示例 1:
输入:price = [13,5,1,8,21,2], k = 3
输出:8
解释:选出价格分别为 [13,5,21] 的三类糖果。
礼盒的甜蜜度为 min(|13 - 5|, |13 - 21|, |5 - 21|) = min(8, 8
, 16) = 8 。
可以证明能够取得的最大甜蜜度就是 8 。
示例 2:
输入:price = [1,3,1], k = 2
输出:2
解释:选出价格分别为 [1,3] 的两类糖果。
礼盒的甜蜜度为 min(|1 - 3|) = min(2) = 2 。
可以证明能够取得的最大甜蜜度就是 2 。
示例 3:
输入:price = [7,7,7,7], k = 2
输出:0
解释:从现有的糖果中任选两类糖果,甜蜜度都会是 0 。
提示:
1 <= price.length <= 10⁵
1 <= price[i] <= 10⁹
2 <= k <= price.length
解题思路 链接到标题
对于这种最小化最大值或者最大化最小值的题目,应该想到二分答案。
由于本题可以任意组合糖果,与糖果之间的顺序无关,因此可以考虑先对 price
数组排序。
记本题的正确答案为 ans
,如果 $mid \leq ans$,那么糖果可以被打包成 $k$ 类糖果礼盒,否则不可以打包成 $k$ 类礼盒,于是我们就找到了满足二分的二段性条件。
同时,我们仍需要使用二分查找来判断是否可以打包成 $k$ 类糖果礼盒,基于排序后的 price
数组。
代码 链接到标题
class Solution {
public:
int Bsearch(int target, vector<int> &price, int left) {
int right = price.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (price[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
bool Check(int mid, vector<int> &price, int k, int n) {
int start = 0;
for (int i = 0; i < k - 1; ++i) {
start = Bsearch(price[start] + mid, price, start);
// cout << start << " start\n";
if (start >= n) {
return false;
}
}
return true;
}
int maximumTastiness(vector<int> &price, int k) {
// 先排序,然后考虑是二分答案还是双指针
sort(price.begin(), price.end());
// 二分答案,时间复杂度为 log(price[i]) * k * log(n)
int n = price.size();
int left = 0, right = (price[n - 1] - price[0]) / (k - 1) + 1; // 先看看 k 行不行,不行就改成 2
while (left < right) {
// 左闭右开
int mid = left + (right - left) / 2;
if (Check(mid, price, k, n)) {
left = mid + 1;
} else {
right = mid;
}
}
return left - 1;
}
};