gorm 0值更新_leetcode第198周赛第四题找到最接近目标值的函数值

leetcode1521. 找到最接近目标值的函数值

3b41e1e5e42d5e314f599c80de83223c.png

Winston 构造了一个如上所示的函数 func 。他有一个整数数组 arr 和一个整数 target ,他想找到让 |func(arr, l, r) - target| 最小的 lr

请你返回 |func(arr, l, r) - target| 的最小值。

请注意, func 的输入参数 lr 需要满足 0 <= l, r < arr.length

示例 1:

输入:arr = [9,12,3,7,15], target = 5
输出:2
解释:所有可能的 [l,r] 数对包括 [[0,0],[1,1],[2,2],[3,3],[4,4],[0,1],[1,2],[2,3],[3,4],[0,2],[1,3],[2,4],[0,3],[1,4],[0,4]], Winston 得到的相应结果为 [9,12,3,7,15,8,0,3,7,0,0,3,0,0,0] 。最接近 5 的值是 7 和 3,所以最小差值为 2 。

示例 2:

输入:arr = [1000000,1000000,1000000], target = 1
输出:999999
解释:Winston 输入函数的所有可能 [l,r] 数对得到的函数值都为 1000000 ,所以最小差值为 999999 。

示例 3:

输入:arr = [1,2,4,8,16], target = 0
输出:0

提示:

  • 1 <= arr.length <= 10^5
  • 1 <= arr[i] <= 10^6
  • 0 <= target <= 10^7

方法:位运算

思路:

首先,我们看func函数的操作,func(arr,l,r),返回的是arr[l]到arr[r]的所有数按位求与。即arr[l]&arr[l+1]&...&arr[r]

设arr长度为n,那么我们暴力的方法,就是建立一个n * n的数组dp,dp[i][j]表示从arr[i]到arr[j]按位求与的值。然后找到满足条件的最小值即可,但是这样方法,时间复杂度接近O(n^2),无法通过。

那么我们需要根据位运算的知识来进行优化,对于按位求与,我们可以得到下面两个性质。

  • a&b&c = a&(b&c) =(a&b)&c,存在结合律。那么我们设求与的最右边的坐标为r,假设以r为右边界的求和值分别为a1、a2、a3、...、an,这些值分别对应着最左边的坐标l=0、1、2...,那么,以r+1为最右坐标的求和值则为a1&arr[r+1]、a2&arr[r+1]、a3&arr[r+1]、...、arr[r+1]。因此,我们对r进行遍历,从0开始,使用一个数组来保存以r为右边界的求与值,那么求r+1为右边界的时候,只需对所有值再对arr[r+1]求与即可,再加上一个arr[r+1],即只一个数的情况。这样,遍历完r,我们也就遍历到了所有值。
  • 上面的方法遍历了所有值,复杂度是没有改变的,但是,以r为右边界的值中,是有重复的,我们使用集合替代数组,计算r+1时,遍历的数为集合中的元素,消去了重复元素,可以大大降低复杂度。因为以r为右边界的求与值,最多只有20个值。这是因为,假设arr[r]的二进制中有n个1,经过与操作后,0肯定不会变,只有1会变,而1也只会变成0;无论arr[r]前面是多少个值求与,都可以看作arr[r]与前面所有数的与的结果,这一个数求与,且可以看做arr[r]从与arr[r-1]求与开始,一步一步向前,如果1变成0则不可逆。因此最多只有n种以arr[r]为右边界求与值结果。根据给定的数据范围,n最大为2

因此,我们就可以使用一个集合来保存目前以r为右边界的所有求与和,根据集合中的值更新res,然后遍历r,不断更新res,最后得到答案。

因为每个r最多有20个值。即logn,所以时间复杂度为O(nlogn)。

空间复杂度为O(logn)。

代码:

class Solution:
    def closestToTarget(self, arr: List[int], target: int) -> int:
        n = len(arr)
        # 目前可能出现的按位求和的值
        values = set()
        # 添加第一个,arr[0],即以0为右边的值,初始化res
        values.add(arr[0])  
        res = abs(arr[0]-target)
        # 遍历剩余的值arr值,计算以arr[i]为right可以得到的按位求与值,更新答案
        for i in range(1,n):
            values = {value & arr[i] for value in values}
            values.add(arr[i])
            res = min(res,min(abs(value-target) for value in values))
        # 返回答案
        return res

结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值