转变数组后最接近目标值的数组和

转变数组后最接近目标值的数组和

leetcode 1300

给你一个整数数组 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
二分查找 + 枚举

我们可以枚举出所有的范围,再进行比较筛选。

由于需要求得的结果是整数,所以可以从 0 开始枚举。
枚举的上届是最大值,因为当 value >= arr 时,数组中所有的元素都不变。就不需要再进行下去了,所得结果不会有变化。

当枚举到 value = x 时,我们需要将数组 arr 中所有小于等于 x 的值保持不变,所有大于 x 的值变为 x。要实现这个操作,我们可以将数组 arr 先进行排序,随后进行二分查找,找出数组 arr 中最小的比 x 大的元素 arr[i]。此时数组的和变为:
a r r [ 0 ] + . . . + a r r [ i − 1 ] + x ∗ ( n − i ) arr[0]+...+arr[i−1]+x∗(n−i) arr[0]+...+arr[i1]+x(ni)

为了加速求和操作,我们可以预处理出数组 arr 的前缀和,这样数组求和的时间复杂度即能降为 O ( 1 ) O(1) O(1)。我们将和与 target 进行比较,同时更新答案即可。

Python 代码如下所示:

def findBestValue(self, arr: List[int], target: int) -> int:
    n = len(arr)
    arr.sort()
    prefix = [0]  # 前缀和,并在前面补 [0]
    for num in arr:
        prefix.append(prefix[-1] + num)
 
    res, diff = 0, float('inf')
    for num in range(0, arr[-1]+1):  # 枚举
        idx = bisect_left(arr, num)
        cur = prefix[idx] + (n-idx) * num
        if abs(cur - target) < diff:
            res, diff = num, abs(cur - target)
    return res

注意前缀和的构造,第一位是 0,长度是 n + 1 n+1 n+1。实际上最后一位并非前缀和,只是数组的和。

来源:转变数组后最接近目标值的数组和


扩展:bisect 模块的用法

bisect 全称为 bisection (二分)算法。

主要有两种用法,6 个函数:

  1. 找到在有序数组的插入点位置,以维持有序。

    • bisect.bisect_left(a, x, lo=0, hi=len(a)) 最后得出的结果在 [lo, hi] 区间内,注意是闭区间,得出 hi 结果还要判断是否能用。
      如果 x 已经在 a 里存在,那么插入点会在已存在元素之前(也就是左边)。
    • bisect.bisect(a, x, lo=0, hi=len(a)) 等价于 bisect.bisect_right(a, x, lo=0, hi=len(a)),与上述函数的区别是:
      返回的插入点是 a 中已存在元素 x 的右侧
  2. 将数插入到一个有序序列里,并维持其有序。

    • bisect.insort_left(a, x, lo=0, hi=len(a)):相当于 a.insert(bisect.bisect_left(a, x, lo, hi), x)。要注意搜索是 O ( log ⁡ n ) O(\log n) O(logn) 的,插入却是 O ( n ) O(n) O(n) 的。
    • bisect.insort(a, x, lo=0, hi=len(a)) 等价于 bisect.insort_right(a, x, lo=0, hi=len(a)),与上面区别是把 x 插入到 a 中已存在元素 x 的右侧。

简单来说 bisect_leftbisect 用于得到索引位置,insort_leftinsort 用于插入数据,长度要增加 1。

来源:bisect — 数组二分查找算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值