LeetCode 1300. 转变数组后最接近目标值的数组和
这个题是昨天的每日一题,昨天太忙了,没来得及写完。但是有了思想,本地上跑了几次发现跑出来的答案又误差就溜掉了。
今天有空了就来填一下坑。
class Solution {
public int findBestValue(int[] arr, int target) {
//先进行排序,取得搜索的边界,边界就是0到数组元素中的最大值
Arrays.sort(arr);
//这个前缀和数组还是非常重要的,这个长度一定要多一,否则就会像之前做的一样搜出来的值不对。
int[] prefixSum = new int[arr.length + 1];
//计算前缀和数组
for(int i = 1; i <= arr.length; i++){
prefixSum[i] = prefixSum[i-1] + arr[i-1];
}
//记录当前与目标值最短的距离
int minDistance = target;
//记录答案
int ans = 0;
for(int i = 0; i <= arr[arr.length-1]; i++){
//首先二分搜索我们取的值在arr数组中的位置。
int cur = helper(arr,i);
//利用前缀和数组计算和。
// 比如说我们有2,3,5 我们取3,题目的意思是大于3的都要变成3,我们上面取的值就是1,那么我们这里就是取前缀和数组下标为1的值
//当然这个会有偏移,实际上是原来的0号数据。然后加上(3-1) * 3,这个的意思是我们数组中的3,5都要变成3。
int sum = prefixSum[cur] + (arr.length - cur) * i;
//判断距离差的大小。
if(Math.abs(target - sum) < minDistance){
ans = i;
minDistance = Math.abs(target - sum);
}
}
return ans;
}
//二分查找模板,很容易
public int helper(int[] arr, int target){
int left = 0;
int right = arr.length-1;
while(left < right){
int mid = left + (right - left)/2;
if(arr[mid] >= target){
right = mid;
}else{
left = mid + 1;
}
}
return right;
}
}
有个很奇怪的地方,自己写的反而不如直接调用系统库中的Arrays.binarySearch()方法快。醉了
说起二分查找 ,这个题的确有点像我之前做过的二分查找变种题,具体请看这里
不过这个题还有更快的方法,就是双重二分查找,我昨天第一次写的时候就是双重二分查找,对于我们寻找的ans进行二分查找,然后在循环体内查找当前可能的答案在arr数组中的位置,等到有时间了我再来补上这个坑。