位运算LogTrick

链接:https://leetcode.cn/problems/find-subarray-with-bitwise-or-closest-to-k/description/
困难:https://leetcode.cn/problems/smallest-subarrays-with-maximum-bitwise-or/description/?envType=daily-question&envId=2025-07-29
找到按位或最接近 K 的子数组
给你一个数组 nums 和一个整数 k 。你需要找到 nums 的一个 子数组 ,满足子数组中所有元素按位或运算 OR 的值与 k 的 绝对差 尽可能 小 。换言之,你需要选择一个子数组 nums[l..r] 满足 |k - (nums[l] OR nums[l + 1] … OR nums[r])| 最小。
请你返回 最小 的绝对差值。
1 | 示例 1:输入:nums = [1,2,4,5], k = 3 |
分析
我们首先想到的是暴力算法,外层循环,从 i=0 开始,从左到右遍历 nums。内层循环,从 j=i−1 开始,从右到左遍历 nums,更新 nums[j]=nums[j] ∣ nums[i]
。
1 | // 暴力算法,会超时 |
这里做了很多无用功,把 nums[i] 对应的集合记作 Ai,如果 Ai是Aj的子集,那么内层循环还需要继续跑吗?不需要。如果 A i
已经是 Aj的子集,那么 Ai必然也是更左边的 A0,A1,A2,⋯,Aj−1的子集。既然 Ai都已经是这些集合的子集了,那么并入操作不会改变这些集合。
完全版
加一个条件即可,nums[j] | x !== nums[j]
1 | var minimumDifference = function(nums, k) { |
按位或最大的最小子数组长度
给你一个长度为 n 下标从 0 开始的数组 nums ,数组中所有数字均为非负整数。对于 0 到 n - 1 之间的每一个下标 i ,你需要找出 nums 中一个 最小 非空子数组,它的起始位置为 i (包含这个位置),同时有 最大 的 按位或运算值。
- 换言之,令 Bij 表示子数组 nums[i…j] 的按位或运算的结果,你需要找到一个起始位置为 i 的最小子数组,这个子数组的按位或运算的结果等于 max(Bik) ,其中 i <= k <= n - 1 。
一个数组的按位或运算值是这个数组里所有数字按位或运算的结果。
请你返回一个大小为 n 的整数数组 answer,其中 answer[i]是开始位置为 i ,按位或运算结果最大,且 最短 子数组的长度。
思路
总体思路一致,外层由左到右进行遍历,内层从右往左进行遍历,注意Ai是Aj的子集的情况。
1 | /** |
- Title: 位运算LogTrick
- Author: tianyi
- Created at : 2025-07-29 09:39:28
- Updated at : 2025-07-29 10:01:08
- Link: https://github.com/ztygod/2025/07/29/位运算LogTrick/
- License: This work is licensed under CC BY-NC-SA 4.0.