当前位置: 首页 > news >正文

位运算题目:找到最接近目标值的函数值

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:找到最接近目标值的函数值

出处:1521. 找到最接近目标值的函数值

难度

8 级

题目描述

要求

函数

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

返回 ∣ func(arr, l, r) − target ∣ \big| \texttt{func(arr, l, r)} - \texttt{target} \big| func(arr, l, r)target 的最小值。

注意 func \texttt{func} func 的输入参数包含 l \texttt{l} l r \texttt{r} r,满足 0 ≤ l, r < arr.length \texttt{0} \le \texttt{l, r} < \texttt{arr.length} 0l, r<arr.length

示例

示例 1:

输入: arr = [9,12,3,7,15], target = 5 \texttt{arr = [9,12,3,7,15], target = 5} arr = [9,12,3,7,15], target = 5
输出: 2 \texttt{2} 2
解释:所有可能的 [l,r] \texttt{[l,r]} [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]] \texttt{[[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]]} [[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] \texttt{[9,12,3,7,15,8,0,3,7,0,0,3,0,0,0]} [9,12,3,7,15,8,0,3,7,0,0,3,0,0,0]。最接近 5 \texttt{5} 5 的值是 7 \texttt{7} 7 3 \texttt{3} 3,所以最小差值为 2 \texttt{2} 2

示例 2:

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

示例 3:

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

数据范围

  • 1 ≤ arr.length ≤ 10 5 \texttt{1} \le \texttt{arr.length} \le \texttt{10}^\texttt{5} 1arr.length105
  • 1 ≤ arr[i] ≤ 10 6 \texttt{1} \le \texttt{arr[i]} \le \texttt{10}^\texttt{6} 1arr[i]106
  • 0 ≤ target ≤ 10 7 \texttt{0} \le \texttt{target} \le \texttt{10}^\texttt{7} 0target107

解法

思路和算法

n n n 表示数组 arr \textit{arr} arr 的长度。如果枚举所有的下标对 ( l , r ) (l, r) (l,r),则时间复杂度至少是 O ( n 2 ) O(n^2) O(n2),该时间复杂度过高,需要优化。

如果子数组的右侧端点 r r r 固定,分别考虑两个左侧端点 l 1 l_1 l1 l 2 l_2 l2 对应的函数值。当 l 1 < l 2 ≤ r l_1 < l_2 \le r l1<l2r 时,记 v 1 = func ( arr , l 1 , r ) v_1 = \textit{func}(\textit{arr}, l_1, r) v1=func(arr,l1,r) v 2 = func ( arr , l 2 , r ) v_2 = \textit{func}(\textit{arr}, l_2, r) v2=func(arr,l2,r),则一定有 v 1 ≤ v 2 v_1 \le v_2 v1v2,理由如下。

对于 c = a & b c = a ~\&~ b c=a & b,考虑二进制表示的每一位,只有当 a a a b b b 在同一位的值都是 1 1 1 时, c c c 在该位的值才是 1 1 1,否则 c c c 在该位的值是 0 0 0,因此 c ≤ a c \le a ca c ≤ b c \le b cb。根据 func \textit{func} func 的定义有 v 1 = v 2 & ( arr [ l 1 ] & arr [ l 1 + 1 ] & … & arr [ l 2 − 1 ] ) v_1 = v_2 ~\&~ (\textit{arr}[l_1] ~\&~ \textit{arr}[l_1 + 1] ~\&~ \ldots ~\&~ \textit{arr}[l_2 - 1]) v1=v2 & (arr[l1] & arr[l1+1] &  & arr[l21]),利用按位与运算的性质可得 v 1 ≤ v 2 v_1 \le v_2 v1v2

因此,当子数组的右侧端点固定时,当左侧端点向左移动时函数值不变或减少,当左侧端点向右移动时函数值不变或增加。当左侧端点向左移动时,函数值的二进制表示的每一位只可能不变或从 1 1 1 变成 0 0 0,不可能从 0 0 0 变成 1 1 1,因此当子数组的右侧端点 r r r 固定时,不同的函数值个数不超过 O ( log ⁡ arr [ r ] ) O(\log \textit{arr}[r]) O(logarr[r])

m m m 表示数组 arr \textit{arr} arr 的最大值。利用上述结论,将数组 arr \textit{arr} arr 中的每个元素作为子数组的右侧端点时只需要考虑 O ( log ⁡ m ) O(\log m) O(logm) 个不同的函数值,不需要考虑 O ( n ) O(n) O(n) 个不同的函数值,可以将时间复杂度从 O ( n 2 ) O(n^2) O(n2) 降低到 O ( n log ⁡ m ) O(n \log m) O(nlogm)

具体做法是,将子数组的右侧端点初始化为 0 0 0,此时函数值为 arr [ 0 ] \textit{arr}[0] arr[0],计算 ∣ arr [ 0 ] − target ∣ \big| \textit{arr}[0] - \textit{target} \big| arr[0]target ,作为函数值与目标值的最小差值。对于 i i i 1 1 1 n − 1 n - 1 n1,将 i i i 作为子数组的右侧端点,当前轮的函数值包括上一轮的每个函数值分别与 arr [ i ] \textit{arr}[i] arr[i] 的按位与运算结果,以及 arr [ i ] \textit{arr}[i] arr[i],计算当前轮的每个函数值与目标值的差的绝对值,更新最小差值。

实现方面,区分上一轮的函数值和当前轮的函数值的做法有多种,可以创建两个列表分别存储上一轮的函数值和当前轮的函数值,也可以使用队列存储函数值。使用队列的做法如下。

  1. 当遍历到 arr [ i ] \textit{arr}[i] arr[i] 时,队列中的元素为上一轮的所有函数值,记录此时队列的大小 size \textit{size} size

  2. size \textit{size} size 个元素出队列,将每个出队列的元素和 arr [ i ] \textit{arr}[i] arr[i] 做按位与运算得到当前轮的函数值,将当前轮的函数值入队列。

  3. 最后将 arr [ i ] \textit{arr}[i] arr[i] 入队列,表示 l = r = i l = r = i l=r=i 的情况下对应的函数值。

将当前轮的函数值入队列时需要排除重复元素。由于遍历函数值的顺序具有单调性,因此相等的函数值在遍历顺序中一定相邻,每次将函数值入队列时判断当前函数值与上一个入队列的函数值是否相等,即可排除重重复元素。

代码

class Solution {public int closestToTarget(int[] arr, int target) {int minDiff = Math.abs(arr[0] - target);Queue<Integer> queue = new ArrayDeque<Integer>();queue.offer(arr[0]);int length = arr.length;for (int i = 1; i < length; i++) {int num = arr[i];int size = queue.size();int lastVal = -1;for (int j = 0; j < size; j++) {int prevVal = queue.poll();int currVal = prevVal & num;if (currVal != lastVal) {minDiff = Math.min(minDiff, Math.abs(currVal - target));queue.offer(currVal);lastVal = currVal;}}if (num != lastVal) {minDiff = Math.min(minDiff, Math.abs(num - target));queue.offer(num);}}return minDiff;}
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ m ) O(n \log m) O(nlogm),其中 n n n 是数组 arr \textit{arr} arr 的长度, m m m 是数组 arr \textit{arr} arr 的最大值。遍历数组的过程中,对于每个元素需要 O ( log ⁡ m ) O(\log m) O(logm) 的时间计算以当前元素作为结尾的所有函数值,因此时间复杂度是 O ( n log ⁡ m ) O(n \log m) O(nlogm)

  • 空间复杂度: O ( log ⁡ m ) O(\log m) O(logm),其中 m m m 是数组 arr \textit{arr} arr 的最大值。空间复杂度主要取决于队列,队列中的元素个数不超过 O ( log ⁡ m ) O(\log m) O(logm)

相关文章:

  • 面试从微前端拓展到iframe是如何通信的
  • 计量——检验与代理变量
  • 【备忘踩坑】Android单元测试中读取测试assets的方法
  • EdgeShard:通过协作边缘计算实现高效的 LLM 推理
  • NY244NY249美光闪存颗粒NY252NY256
  • U9C与钉钉审批流对接完整过程
  • 数据结构—排序(斐波那契数列,冒泡,选择,插入,快速,归并,图,广度优先算法)
  • 【Docker】Docker安装Redis
  • Git命令总结
  • 2025年大厂C++面试题总结与解析
  • 【C++】解析C++面向对象三要素:封装、继承与多态实现机制
  • Remote Desktop安卓远程无法使用中文输入法
  • deepseek讲解如何快速解决内存泄露,内存溢出问题
  • C#数据类型
  • Python中常用的数据类型
  • 反向传播
  • 2、ubantu系统配置OpenSSH | 使用vscode或pycharm远程连接
  • 软件设计师考试《综合知识》CPU考点分析(2019-2023年)——求三连
  • 【QT 项目部署指南】使用 Inno Setup 打包 QT 程序为安装包(超详细图文教程)
  • 基于EFISH-SCB-RK3576/SAIL-RK3576的消防机器人控制器技术方案‌
  • 河南信阳:对违规吃喝问题不遮丑不护短,露头就打、反复敲打
  • 奥运“四朝元老”华天回国参赛,伤势未愈谨慎出战全国锦标赛
  • 获派驻6年后,中国驻厄瓜多尔大使陈国友即将离任
  • 中国海警舰艇编队5月14日在我钓鱼岛领海巡航
  • 回望乡土:对媒介化社会的反思
  • 吉林:消纳绿电,“氢”装上阵