问题一:转变数组后最接近目标值的数组和(leetcode1300)
问题描述:
给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。
如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。
请注意,答案不一定是 arr 中的数字。
示例 1:
输入:arr = [4,9,3], target = 10
输出:3
解释:当选择 value 为 3 时,数组会变成 [3, 3, 3],和为 9 ,这是最接近 target 的方案。
示例 2:
输入:arr = [2,3,5], target = 10
输出:5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-mutated-array-closest-to-target
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决方案:
由题可知,value值越大转化后数组和也就越大。先找到value上下界,再按照该规律二分查找数组和最接近target的value值;下界为0,上界为max(arr)
若此时给定一个value得到一个数组和,若该数组和大于等于target,说明解在该值的左边
若小于target时,最优解在该值的右边。
注:由于想要找到最小的value所以等于时应在其之前继续寻找
实现代码如下:
class Solution {
public int findBestValue(int[] arr, int target) {
int left = 0;
int right = Integer.MIN_VALUE;
for(int num : arr){
right = Math.max(right, num);
}
while(left < right - 1){
int mid = left + (right - left) / 2;
if(getSum(arr, mid) >= target){
right = mid;
}else{
left = mid;
}
}
if(Math.abs(getSum(arr, left) - target) <= Math.abs(getSum(arr, right) - target)){
return left;
}
return right;
}
public int getSum(int[] arr, int val){
int sum = 0;
for(int num : arr){
sum += num > val ? val : num;
}
return sum;
}
}
问题二:制作m束花所需的最小天数(leetcode5438)
问题描述:
给你一个整数数组 bloomDay,以及两个整数 m 和 k 。
现需要制作 m 束花。制作花束时,需要使用花园中 相邻的 k 朵花 。
花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好 可以用于 一束 花中。
请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-number-of-days-to-make-m-bouquets
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决方案:
辛亏今早周赛前把每日一题(问题一)做了,然后做这个问题亦很容易的想到二分+贪心的策略。由题意可知,当t天可以摘m束花时,则比t大的天数亦可以摘m束花,根据这一规律,先找到上下界(上界为max(bloomDay), 下界为min(bloomDay)),然后采用二分查找,此外判断给定的天数能否摘m束花时,就是看当前天数下,是否有m对k个一连的花。
代码如下:
class Solution {
public int minDays(int[] bloomDay, int m, int k) {
if(bloomDay.length < m * k){
return -1;
}
int left = bloomDay[0];
int right = bloomDay[0];
for(int num : bloomDay){
left = Math.min(left, num);
right = Math.max(right, num);
}
while(left < right - 1){
int mid = left + (right - left) / 2;
if(process(bloomDay, m, k, mid)){
right = mid;
}else{
left = mid;
}
}
if(process(bloomDay, m, k, left)){
return left;
}
return right;
}
public boolean process(int[] bloomDay, int m, int k, int day){
int i = 0;
while(i < bloomDay.length){
for(int j = 0; j < k && i < bloomDay.length; j++, i++){
if(bloomDay[i] > day){
i++;
break;
}
if(j == k - 1 && bloomDay[i] <= day){
m--;
}
}
}
// System.out.println(day + " " + m);
return m <= 0;
}
}
ps:这两个问题都在找满足条件的最小值。