【Leetcode 每日一题 - 扩展】3171. 找到按位或最接近 K 的子数组

server/2025/1/18 1:29:11/

问题背景

给你一个数组 n u m s nums nums 和一个整数 k k k。你需要找到 n u m s nums nums 的一个 子数组 ,满足子数组中所有元素按位或运算 O R OR OR 的值与 k k k绝对差 尽可能 。换言之,你需要选择一个子数组 n u m s [ l . . r ] nums[l..r] nums[l..r] 满足 ∣ k − ( n u m s [ l ] O R n u m s [ l + 1 ] . . . O R n u m s [ r ] ) ∣ |k - (nums[l] OR nums[l + 1] ... OR nums[r])| k(nums[l]ORnums[l+1]...ORnums[r]) 最小。
请你返回 最小 的绝对差值。
子数组 是数组中连续的 非空 元素序列。

数据约束

  • 1 ≤ n u m s . l e n g t h ≤ 1 0 5 1 \le nums.length \le 10 ^ 5 1nums.length105
  • 1 ≤ n u m s [ i ] ≤ 1 0 9 1 \le nums[i] \le 10 ^ 9 1nums[i]109
  • 1 ≤ k ≤ 1 0 9 1 \le k \le 10 ^ 9 1k109

解题过程

这题是对数组元素进行某种操作后按照某种标准求子数组的模板题,这类问题的特点就是通常要求的操作没有逆运算,例如这里的或运算,它的逆运算是不容易实现的。
解决方案有两个,一是使用 LogTrick,找了一圈没找到出处在哪里,那还是贴一下 灵神题解。大体上思路是在嵌套循环的基础上,跳过明显不可能是结果的情形,有点像剪枝。在这题中,如果循环中遇到的新元素没能增加运算结果,那它也不可能在更大范围内产生不同的情形,可以跳出内层循环。
这种做法,可以将时间复杂度从 O ( N 2 ) O(N ^ 2) O(N2) 优化到 O ( N l o g U ) O(NlogU) O(NlogU),其中 U U U 是数组中的最大值。

另一种思路当然是滑窗,需要解决元素排除出窗口这个操作的实现,实际上用到了类似栈的思想,数组 n u m s [ i ] nums[i] nums[i] 记录的是 n u m s [ i ] ∣ n u m s [ i − 1 ] . . . ∣ n u m s [ 0 ] nums[i]|nums[i - 1]...|nums[0] nums[i]nums[i1]...∣nums[0] 的结果。
多定义一个变量 b o t t o m bottom bottom,避免不必要的数据更新操作。

具体实现

LogTrick

class Solution {public int minimumDifference(int[] nums, int k) {int res = Integer.MAX_VALUE;for(int i = 0; i < nums.length; i++) {int cur = nums[i];res = Math.min(res, Math.abs(cur - k));// 和暴力解的区别就在于多进行了一个判断,去掉了不必要的遍历for(int j = i - 1; j >= 0 && (nums[j] | cur) != nums[j]; j--) {nums[j] |= cur;res = Math.min(res, Math.abs(nums[j] - k));}}return res;}
}

滑动窗口

class Solution {public int minimumDifference(int[] nums, int k) {int res = Integer.MAX_VALUE;int bottom = 0;int rightOr = 0;for(int left = 0, right = 0; right < nums.length; right++) {// 元素从窗口右侧进入rightOr |= nums[right];while(left <= right && (nums[left] | rightOr) > k) {// 循环条件保证了 (nums[left++] | rightOr) 大于 k,相应地更新结果res = Math.min(res, (nums[left++] | rightOr) - k);// bottom 始终指向栈底,它在窗口之外表示 rightOr 的结果没有被 nums 数组记录if(bottom < left) {// 遍历并把结果更新到 nums 数组中for(int i = right - 1; i >= left; i--) {nums[i] |= nums[i + 1];}// 更新栈底指针bottom = right;// 重置右侧或运算结果rightOr = 0;}}// 内层循环结束,表示 left <= right 或 (nums[left] | rightOr) > k 条件被打破if(left <= right) {// 循环条件保证了 k 大于 (nums[left++] | rightOr),在合法的情况下更新结果res = Math.min(res, k - (nums[left] | rightOr));}}return res;}
}

http://www.ppmy.cn/server/159221.html

相关文章

接口自动化入门 : Http的请求头,请求体,响应码解忻!

在进行接口自动化测试时&#xff0c;你需要了解Http的请求头、请求体和响应码的解析。 本文从3个方面介绍这篇文章 一、Http的请求头 二、请求体 三、响应码解忻 一、Http的请求头 HTTP 请求头是 HTTP 请求中的一部分&#xff0c;用于向服务器传递附加的信息。它包含在 HTTP …

2025 年将是统一网络安全的一年

到 2025 年&#xff0c;网络安全将不再只是 IT 团队专属的技术主题&#xff0c;而是将日益成为董事会层面的优先事项。随着网络攻击的频率和严重性不断增加&#xff0c;董事会将需要能够让他们了解组织安全状况的平台。 Armis 首席执行官 Yevgeny Dibrov 认为&#xff0c;统一网…

C# OpenCV机器视觉:极大值抑制

在一个阳光有些慵懒的午后&#xff0c;阿强像往常一样窝在他那被各种电子元件和线路堆满的实验室里&#xff0c;周围的电脑屏幕闪烁着神秘的代码和复杂的图像&#xff0c;仿佛在诉说着一个个未被解开的科技谜题。阿强最近痴迷于机器视觉领域&#xff0c;而今天&#xff0c;他将…

自动化办公|xlwings简介

xlwings 是一个开源的 Python 库&#xff0c;旨在实现 Python 与 Microsoft Excel 的无缝集成。它允许用户使用 Python 脚本自动化 Excel 操作&#xff0c;读取和写入数据&#xff0c;执行宏&#xff0c;甚至调用 VBA 脚本。这使得数据分析、报告生成和其他与 Excel 相关的任务…

大模型-第三章Prompt工程

快速上手大模型 from zhipuai import ZhipuAI client ZhipuAI(api_key"") # 填写您自己的APIKey response client.chat.completions.create(model"glm-4-plus", # 填写需要调用的模型编码messages[{"role": "system", "conte…

关于vite+vue3+ts项目中env.d.ts 文件详解

env.d.ts 文件是 Vite 项目中用于定义全局类型声明的 TypeScript 文件。它帮助开发者向 TypeScript提供全局的类型提示&#xff0c;特别是在使用一些特定于 Vite 的功能时&#xff08;如 import.meta.env&#xff09;。以下是详细讲解及代码示例 文章目录 **1. env.d.ts 文件的…

MiniCPM-o 2.6:开源大型语言模型在多模态任务上超越GPT-4o和Claude 3.5

MiniCPM-o 2.6是一款开源的大型语言模型&#xff08;LLM&#xff09;&#xff0c;其在多模态任务上的表现令人瞩目&#xff0c;成功超越了GPT-4o和Claude 3.5等业界知名模型。以下是对MiniCPM-o 2.6的详细介绍&#xff1a; 一、卓越的多模态能力 MiniCPM-o 2.6采用了先进的端…

初学stm32 --- CAN

目录 CAN介绍 CAN总线拓扑图 CAN总线特点 CAN应用场景 CAN物理层 CAN收发器芯片介绍 CAN协议层 数据帧介绍 CAN位时序介绍 数据同步过程 硬件同步 再同步 CAN总线仲裁 STM32 CAN控制器介绍 CAN控制器模式 CAN控制器模式 CAN控制器框图 发送处理 接收处理 接收过…