Skip to content

Commit b0f757b

Browse files
authored
feat: update solutions to lc problems: No.3171,3209 (#3227)
* No.3209.Number of Subarrays With AND Value of K * No.3171.Find Subarray With Bitwise OR Closest to K
1 parent 6f425ec commit b0f757b

File tree

19 files changed

+395
-181
lines changed

19 files changed

+395
-181
lines changed

solution/3100-3199/3171.Find Subarray With Bitwise OR Closest to K/README.md

+49-59
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@ tags:
8383

8484
### 方法一:双指针 + 位运算
8585

86-
根据题目描述,我们需要求出数组 $nums$ 下标 $l$ 到 $r$ 的元素的按位与运算的结果,即 $nums[l] \& nums[l + 1] \& \cdots \& nums[r]$。
86+
根据题目描述,我们需要求出数组 $\textit{nums}$ 下标 $l$ 到 $r$ 的元素的按位或运算的结果,即 $\textit{nums}[l] \lor \textit{nums}[l + 1] \lor \cdots \lor \textit{nums}[r]$。其中 $\lor$ 表示按位或运算
8787

88-
如果我们每次固定右端点 $r$,那么左端点 $l$ 的范围是 $[0, r]$。每次移动右端点 $r$,按位与的结果只会变小,我们用一个变量 $s$ 记录当前的按位与的结果,如果 $s$ 小于 $k$,我们就将左端点 $l$ 向右移动,直到 $s$ 大于等于 $k$。在移动左端点 $l$ 的过程中,我们需要维护一个数组 $cnt$,记录当前区间内每个二进制位上 $0$ 的个数,当 $cnt[h]$ 为 $0$ 时,说明当前区间内的元素在第 $h$ 位上都为 $1$,我们就可以将 $s$ 的第 $h$ 位设置为 $1$。
88+
如果我们每次固定右端点 $r$,那么左端点 $l$ 的范围是 $[0, r]$。每次移动右端点 $r$,按位或的结果只会变大,我们用一个变量 $s$ 记录当前的按位或的结果,如果 $s$ 大于 $k$,我们就将左端点 $l$ 向右移动,直到 $s$ 小于等于 $k$。在移动左端点 $l$ 的过程中,我们需要维护一个数组 $cnt$,记录当前区间内每个二进制位上 $0$ 的个数,当 $cnt[h]$ 为 $0$ 时,说明当前区间内的元素在第 $h$ 位上都为 $1$,我们就可以将 $s$ 的第 $h$ 位设置为 $0$。
8989

90-
时间复杂度 $O(n \times \log M)$,空间复杂度 $O(\log M)$。其中 $n$ 和 $M$ 分别是数组 $nums$ 的长度和数组 $nums$ 中的最大值
90+
时间复杂度 $O(n \times \log M)$,空间复杂度 $O(\log M)$。其中 $n$ 和 $M$ 分别是数组 $\textit{nums}$ 的长度和数组 $\textit{nums}$ 中元素的最大值
9191

9292
相似题目:
9393

@@ -102,21 +102,21 @@ class Solution:
102102
def minimumDifference(self, nums: List[int], k: int) -> int:
103103
m = max(nums).bit_length()
104104
cnt = [0] * m
105-
s, i = -1, 0
105+
s = i = 0
106106
ans = inf
107107
for j, x in enumerate(nums):
108-
s &= x
108+
s |= x
109109
ans = min(ans, abs(s - k))
110110
for h in range(m):
111-
if x >> h & 1 ^ 1:
111+
if x >> h & 1:
112112
cnt[h] += 1
113-
while i < j and s < k:
113+
while i < j and s > k:
114114
y = nums[i]
115115
for h in range(m):
116-
if y >> h & 1 ^ 1:
116+
if y >> h & 1:
117117
cnt[h] -= 1
118118
if cnt[h] == 0:
119-
s |= 1 << h
119+
s ^= 1 << h
120120
i += 1
121121
ans = min(ans, abs(s - k))
122122
return ans
@@ -135,18 +135,18 @@ class Solution {
135135
int[] cnt = new int[m];
136136
int n = nums.length;
137137
int ans = Integer.MAX_VALUE;
138-
for (int i = 0, j = 0, s = -1; j < n; ++j) {
139-
s &= nums[j];
138+
for (int i = 0, j = 0, s = 0; j < n; ++j) {
139+
s |= nums[j];
140140
ans = Math.min(ans, Math.abs(s - k));
141141
for (int h = 0; h < m; ++h) {
142-
if ((nums[j] >> h & 1) == 0) {
142+
if ((nums[j] >> h & 1) == 1) {
143143
++cnt[h];
144144
}
145145
}
146-
while (i < j && s < k) {
146+
while (i < j && s > k) {
147147
for (int h = 0; h < m; ++h) {
148-
if ((nums[i] >> h & 1) == 0 && --cnt[h] == 0) {
149-
s |= 1 << h;
148+
if ((nums[i] >> h & 1) == 1 && --cnt[h] == 0) {
149+
s ^= 1 << h;
150150
}
151151
}
152152
++i;
@@ -169,18 +169,18 @@ public:
169169
int n = nums.size();
170170
int ans = INT_MAX;
171171
vector<int> cnt(m);
172-
for (int i = 0, j = 0, s = -1; j < n; ++j) {
173-
s &= nums[j];
172+
for (int i = 0, j = 0, s = 0; j < n; ++j) {
173+
s |= nums[j];
174174
ans = min(ans, abs(s - k));
175175
for (int h = 0; h < m; ++h) {
176-
if (nums[j] >> h & 1 ^ 1) {
176+
if (nums[j] >> h & 1) {
177177
++cnt[h];
178178
}
179179
}
180-
while (i < j && s < k) {
180+
while (i < j && s > k) {
181181
for (int h = 0; h < m; ++h) {
182-
if (nums[i] >> h & 1 ^ 1 && --cnt[h] == 0) {
183-
s |= 1 << h;
182+
if (nums[i] >> h & 1 && --cnt[h] == 0) {
183+
s ^= 1 << h;
184184
}
185185
}
186186
ans = min(ans, abs(s - k));
@@ -199,22 +199,22 @@ func minimumDifference(nums []int, k int) int {
199199
m := bits.Len(uint(slices.Max(nums)))
200200
cnt := make([]int, m)
201201
ans := math.MaxInt32
202-
s, i := -1, 0
202+
s, i := 0, 0
203203
for j, x := range nums {
204-
s &= x
204+
s |= x
205205
ans = min(ans, abs(s-k))
206206
for h := 0; h < m; h++ {
207-
if x>>h&1 == 0 {
207+
if x>>h&1 == 1 {
208208
cnt[h]++
209209
}
210210
}
211-
for i < j && s < k {
211+
for i < j && s > k {
212212
y := nums[i]
213213
for h := 0; h < m; h++ {
214-
if y>>h&1 == 0 {
214+
if y>>h&1 == 1 {
215215
cnt[h]--
216216
if cnt[h] == 0 {
217-
s |= 1 << h
217+
s ^= 1 << h
218218
}
219219
}
220220
}
@@ -239,20 +239,20 @@ func abs(x int) int {
239239
function minimumDifference(nums: number[], k: number): number {
240240
const m = Math.max(...nums).toString(2).length;
241241
const n = nums.length;
242-
const cnt: number[] = numsay(m).fill(0);
242+
const cnt: number[] = Array(m).fill(0);
243243
let ans = Infinity;
244-
for (let i = 0, j = 0, s = -1; j < n; ++j) {
245-
s &= nums[j];
244+
for (let i = 0, j = 0, s = 0; j < n; ++j) {
245+
s |= nums[j];
246246
ans = Math.min(ans, Math.abs(s - k));
247247
for (let h = 0; h < m; ++h) {
248-
if (((nums[j] >> h) & 1) ^ 1) {
248+
if ((nums[j] >> h) & 1) {
249249
++cnt[h];
250250
}
251251
}
252-
while (i < j && s < k) {
252+
while (i < j && s > k) {
253253
for (let h = 0; h < m; ++h) {
254-
if (((nums[i] >> h) & 1) ^ 1 && --cnt[h] === 0) {
255-
s |= 1 << h;
254+
if ((nums[i] >> h) & 1 && --cnt[h] === 0) {
255+
s ^= 1 << h;
256256
}
257257
}
258258
ans = Math.min(ans, Math.abs(s - k));
@@ -271,9 +271,9 @@ function minimumDifference(nums: number[], k: number): number {
271271

272272
### 方法二:哈希表 + 枚举
273273

274-
根据题目描述,我们需要求出数组 $nums$ 下标 $l$ 到 $r$ 的元素的按位与运算的结果,即 $nums[l] \& nums[l + 1] \& \cdots \& nums[r]$。
274+
根据题目描述,我们需要求出数组 $nums$ 下标 $l$ 到 $r$ 的元素的按位或运算的结果,即 $nums[l] \lor nums[l + 1] \lor \cdots \lor nums[r]$。其中 $\lor$ 表示按位或运算
275275

276-
如果我们每次固定右端点 $r$,那么左端点 $l$ 的范围是 $[0, r]$。由于按位与之和随着 $l$ 的减小而单调递减,并且 $nums[i]$ 的值不超过 $10^9$,因此区间 $[0, r]$ 最多只有 $30$ 种不同的值。因此,我们可以用一个集合来维护所有的 $nums[l] \& nums[l + 1] \& \cdots \& nums[r]$ 的值。当我们从 $r$ 遍历到 $r+1$ 时,以 $r+1$ 为右端点的值,就是集合中每个值与 $nums[r + 1]$ 进行按位与运算得到的值,再加上 $nums[r + 1]$ 本身。因此,我们只需要枚举集合中的每个值,与 $nums[r]$ 进行按位与运算,就可以得到以 $r$ 为右端点的所有值,将每个值与 $k$ 相减后取绝对值,就可以得到以 $r$ 为右端点的所有值与 $k$ 的差的绝对值,其中的最小值就是答案。
276+
如果我们每次固定右端点 $r$,那么左端点 $l$ 的范围是 $[0, r]$。由于按位或之和随着 $l$ 的减小而单调递增,并且 $\textit{nums}[i]$ 的值不超过 $10^9$,因此区间 $[0, r]$ 最多只有 $30$ 种不同的值。因此,我们可以用一个集合来维护所有的 $nums[l] \lor nums[l + 1] \lor \cdots \lor nums[r]$ 的值。当我们从 $r$ 遍历到 $r+1$ 时,以 $r+1$ 为右端点的值,就是集合中每个值与 $nums[r + 1]$ 进行按位或运算得到的值,再加上 $nums[r + 1]$ 本身。因此,我们只需要枚举集合中的每个值,与 $nums[r]$ 进行按位或运算,就可以得到以 $r$ 为右端点的所有值,将每个值与 $k$ 相减后取绝对值,就可以得到以 $r$ 为右端点的所有值与 $k$ 的差的绝对值,其中的最小值就是答案。
277277

278278
时间复杂度 $O(n \times \log M)$,空间复杂度 $O(\log M)$。其中 $n$ 和 $M$ 分别是数组 $nums$ 的长度和数组 $nums$ 中的最大值。
279279

@@ -288,10 +288,10 @@ function minimumDifference(nums: number[], k: number): number {
288288
```python
289289
class Solution:
290290
def minimumDifference(self, nums: List[int], k: int) -> int:
291-
ans = abs(nums[0] - k)
292-
s = {nums[0]}
291+
ans = inf
292+
s = set()
293293
for x in nums:
294-
s = {x & y for y in s} | {x}
294+
s = {x | y for y in s} | {x}
295295
ans = min(ans, min(abs(y - k) for y in s))
296296
return ans
297297
```
@@ -301,13 +301,12 @@ class Solution:
301301
```java
302302
class Solution {
303303
public int minimumDifference(int[] nums, int k) {
304-
int ans = Math.abs(nums[0] - k);
304+
int ans = Integer.MAX_VALUE;
305305
Set<Integer> pre = new HashSet<>();
306-
pre.add(nums[0]);
307306
for (int x : nums) {
308307
Set<Integer> cur = new HashSet<>();
309308
for (int y : pre) {
310-
cur.add(x & y);
309+
cur.add(x | y);
311310
}
312311
cur.add(x);
313312
for (int y : cur) {
@@ -326,14 +325,13 @@ class Solution {
326325
class Solution {
327326
public:
328327
int minimumDifference(vector<int>& nums, int k) {
329-
int ans = abs(nums[0] - k);
328+
int ans = INT_MAX;
330329
unordered_set<int> pre;
331-
pre.insert(nums[0]);
332330
for (int x : nums) {
333331
unordered_set<int> cur;
334332
cur.insert(x);
335333
for (int y : pre) {
336-
cur.insert(x & y);
334+
cur.insert(x | y);
337335
}
338336
for (int y : cur) {
339337
ans = min(ans, abs(y - k));
@@ -349,41 +347,33 @@ public:
349347
350348
```go
351349
func minimumDifference(nums []int, k int) int {
352-
ans := abs(nums[0] - k)
353-
pre := map[int]bool{nums[0]: true}
350+
ans := math.MaxInt32
351+
pre := map[int]bool{}
354352
for _, x := range nums {
355353
cur := map[int]bool{x: true}
356354
for y := range pre {
357-
cur[x&y] = true
355+
cur[x|y] = true
358356
}
359357
for y := range cur {
360-
ans = min(ans, abs(y-k))
358+
ans = min(ans, max(y-k, k-y))
361359
}
362360
pre = cur
363361
}
364362
return ans
365363
}
366-
367-
func abs(x int) int {
368-
if x < 0 {
369-
return -x
370-
}
371-
return x
372-
}
373364
```
374365

375366
#### TypeScript
376367

377368
```ts
378369
function minimumDifference(nums: number[], k: number): number {
379-
let ans = Math.abs(nums[0] - k);
370+
let ans = Infinity;
380371
let pre = new Set<number>();
381-
pre.add(nums[0]);
382372
for (const x of nums) {
383373
const cur = new Set<number>();
384374
cur.add(x);
385375
for (const y of pre) {
386-
cur.add(x & y);
376+
cur.add(x | y);
387377
}
388378
for (const y of cur) {
389379
ans = Math.min(ans, Math.abs(y - k));

0 commit comments

Comments
 (0)