ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

力扣【二分查找】:1300. 转变数组后最接近目标值的数组和

力扣【二分查找】:1300. 转变数组后最接近目标值的数组和
  1. 题目描述:

给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。

如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

请注意,答案不一定是 arr 中的数字。

  1. 算法思路:

题目要求我们找到使得替换所有大于value的数之后,arr的数组和与target最接近的value,那么我们可以先确认value的范围,

由于题目给定的限制条件:1 <= arr.length <= 10^4,1 <= arr[i], target <= 10^5,那么如果value < 0,那么数组arr求和的值和target的绝对值只会变大,

所以value一定大于等于0,设想这样一个数组,它的长度很大使得即便value为1时它的数组和与target的绝对值依然大于target本身,那么这是value = 0就是绝对值最小的情况,

又因为可以替换为value的是arr中大于value的值,如果value 大于max(arr),则不会替换任何元素,也不会缩小绝对值,

所以value的最大值应该是max(arr),

因此0 <= value <= max(arr),这里具有有序性,所以可以使用二分查找的方式,

在每次二分时遍历数组计算arr和,

如果arr和小于target,则说明value可以变大,反之如果arr和大于target,则value可以减小,这样不断向绝对值0的反向趋近,

value只在绝对值结果变小时更新,如果绝对值相同则value等于新旧value中较小的一个,

  1. 代码:

时间复杂度:设二分边界为m,数组长度为n,O(n log (m))

int findBestValue(vector<int>& arr, int target) {int lower_bound = 0, upper_bound = *std::max_element(arr.begin(), arr.end());int result = *std::max_element(arr.begin(), arr.end());int abs = std::abs(target - std::accumulate(arr.begin(), arr.end(), 0));while (lower_bound < upper_bound) {int mid = lower_bound + (upper_bound - lower_bound) / 2;int sum = 0;for (const int &n : arr) {if (n > mid) {sum += mid;} else {sum += n;}}if (sum < target) {lower_bound = mid + 1;} else {upper_bound = mid;}int new_abs = std::abs(sum - target);if (new_abs < abs) {abs = new_abs;result = mid;} else if (new_abs == abs) {result = std::min(mid, result);}}return result;}
返回列表