[LeetCode]1300.转变数组后最接近目标值的数组和
解法
由于arr[i]的范围是 [ 1 , 1 0 5 ] [1,10^5] [1,105]所以可以使用枚举法来寻找合适的value值,那么就需要确定value的上下限。
- 当value=0时数组内元数都小于value,如果value继续减小,则数组元素之和也不会改变,所以value下限为0
- 当value>=数组内元素最大值时,数组元素之和也不会改变所以value上限为数组元素最大值。
确定value上下限后就可以枚举,当value=x时需要找出arr中刚好比x大的值a[i],arr中小于x的部分不变,大于等于x的值变为x,数组之和公式为:
a
[
0
]
+
.
.
.
+
a
[
i
−
1
]
+
(
n
−
i
)
∗
x
a[0]+...+a[i-1]+(n-i)*x
a[0]+...+a[i−1]+(n−i)∗x
可以预处理数组的前缀和,这样数组求和的时间复杂度降到o(1),将数组和与target比较不断更新即可。
class Solution {
public int findBestValue(int[] arr, int target) {
Arrays.sort(arr);//二分查找之前对数组进行排序
int n = arr.length;
int[] prefix = new int[n+1];
//提前计算好前缀之和存放到数组中
for(int i = 1; i <= n; i++){
prefix[i] = prefix[i - 1] + arr[i - 1];
}
int ans = 0;
int r = arr[n-1];//value的上限
int diff = target;
for(int value = 1; value <= r; value++){//枚举查询arr中刚好大于value的值
int index = Arrays.binarySearch(arr,value);
if(index < 0){//搜索值不是数组元数,且大于数组内元数返回-(length + 1);
//不是数组元数,且小于数组内元数返回-1;在数组范围内则得到“-插入点索引值”
index = -index - 1;
}
int cur = prefix[index] + value * (n - index);
if(Math.abs(cur - target) < diff){
ans = value;
diff = Math.abs(cur - target);
}
}
return ans;
}
}
注
binarySearch(Object[] a, Object key)
a
: 要搜索的数组
key
:要搜索的值
如果key在数组中,则返回搜索值的索引;否则返回-1或“-”(插入点)。插入点是索引键将要插入数组的那一点,即第一个大于该键的元素的索引。
技巧:
-
搜索值不是数组元素,且在数组范围内,从1开始计数,得“ - 插入点索引值”;
-
搜索值是数组元素,从0开始计数,得搜索值的索引值;
-
搜索值不是数组元素,且大于数组内元素,索引值为 – (length + 1);
-
搜索值不是数组元素,且小于数组内元素,索引值为 – 1。