Skip to content

Commit

Permalink
feat: update solutions to lc problems: No.3171,3209 (#3227)
Browse files Browse the repository at this point in the history
* No.3209.Number of Subarrays With AND Value of K
* No.3171.Find Subarray With Bitwise OR Closest to K
  • Loading branch information
yanglbme authored Jul 8, 2024
1 parent 6f425ec commit b0f757b
Show file tree
Hide file tree
Showing 19 changed files with 395 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ tags:

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

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

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

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

相似题目:

Expand All @@ -102,21 +102,21 @@ class Solution:
def minimumDifference(self, nums: List[int], k: int) -> int:
m = max(nums).bit_length()
cnt = [0] * m
s, i = -1, 0
s = i = 0
ans = inf
for j, x in enumerate(nums):
s &= x
s |= x
ans = min(ans, abs(s - k))
for h in range(m):
if x >> h & 1 ^ 1:
if x >> h & 1:
cnt[h] += 1
while i < j and s < k:
while i < j and s > k:
y = nums[i]
for h in range(m):
if y >> h & 1 ^ 1:
if y >> h & 1:
cnt[h] -= 1
if cnt[h] == 0:
s |= 1 << h
s ^= 1 << h
i += 1
ans = min(ans, abs(s - k))
return ans
Expand All @@ -135,18 +135,18 @@ class Solution {
int[] cnt = new int[m];
int n = nums.length;
int ans = Integer.MAX_VALUE;
for (int i = 0, j = 0, s = -1; j < n; ++j) {
s &= nums[j];
for (int i = 0, j = 0, s = 0; j < n; ++j) {
s |= nums[j];
ans = Math.min(ans, Math.abs(s - k));
for (int h = 0; h < m; ++h) {
if ((nums[j] >> h & 1) == 0) {
if ((nums[j] >> h & 1) == 1) {
++cnt[h];
}
}
while (i < j && s < k) {
while (i < j && s > k) {
for (int h = 0; h < m; ++h) {
if ((nums[i] >> h & 1) == 0 && --cnt[h] == 0) {
s |= 1 << h;
if ((nums[i] >> h & 1) == 1 && --cnt[h] == 0) {
s ^= 1 << h;
}
}
++i;
Expand All @@ -169,18 +169,18 @@ public:
int n = nums.size();
int ans = INT_MAX;
vector<int> cnt(m);
for (int i = 0, j = 0, s = -1; j < n; ++j) {
s &= nums[j];
for (int i = 0, j = 0, s = 0; j < n; ++j) {
s |= nums[j];
ans = min(ans, abs(s - k));
for (int h = 0; h < m; ++h) {
if (nums[j] >> h & 1 ^ 1) {
if (nums[j] >> h & 1) {
++cnt[h];
}
}
while (i < j && s < k) {
while (i < j && s > k) {
for (int h = 0; h < m; ++h) {
if (nums[i] >> h & 1 ^ 1 && --cnt[h] == 0) {
s |= 1 << h;
if (nums[i] >> h & 1 && --cnt[h] == 0) {
s ^= 1 << h;
}
}
ans = min(ans, abs(s - k));
Expand All @@ -199,22 +199,22 @@ func minimumDifference(nums []int, k int) int {
m := bits.Len(uint(slices.Max(nums)))
cnt := make([]int, m)
ans := math.MaxInt32
s, i := -1, 0
s, i := 0, 0
for j, x := range nums {
s &= x
s |= x
ans = min(ans, abs(s-k))
for h := 0; h < m; h++ {
if x>>h&1 == 0 {
if x>>h&1 == 1 {
cnt[h]++
}
}
for i < j && s < k {
for i < j && s > k {
y := nums[i]
for h := 0; h < m; h++ {
if y>>h&1 == 0 {
if y>>h&1 == 1 {
cnt[h]--
if cnt[h] == 0 {
s |= 1 << h
s ^= 1 << h
}
}
}
Expand All @@ -239,20 +239,20 @@ func abs(x int) int {
function minimumDifference(nums: number[], k: number): number {
const m = Math.max(...nums).toString(2).length;
const n = nums.length;
const cnt: number[] = numsay(m).fill(0);
const cnt: number[] = Array(m).fill(0);
let ans = Infinity;
for (let i = 0, j = 0, s = -1; j < n; ++j) {
s &= nums[j];
for (let i = 0, j = 0, s = 0; j < n; ++j) {
s |= nums[j];
ans = Math.min(ans, Math.abs(s - k));
for (let h = 0; h < m; ++h) {
if (((nums[j] >> h) & 1) ^ 1) {
if ((nums[j] >> h) & 1) {
++cnt[h];
}
}
while (i < j && s < k) {
while (i < j && s > k) {
for (let h = 0; h < m; ++h) {
if (((nums[i] >> h) & 1) ^ 1 && --cnt[h] === 0) {
s |= 1 << h;
if ((nums[i] >> h) & 1 && --cnt[h] === 0) {
s ^= 1 << h;
}
}
ans = Math.min(ans, Math.abs(s - k));
Expand All @@ -271,9 +271,9 @@ function minimumDifference(nums: number[], k: number): number {

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

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

如果我们每次固定右端点 $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$ 的差的绝对值,其中的最小值就是答案。
如果我们每次固定右端点 $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$ 的差的绝对值,其中的最小值就是答案。

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

Expand All @@ -288,10 +288,10 @@ function minimumDifference(nums: number[], k: number): number {
```python
class Solution:
def minimumDifference(self, nums: List[int], k: int) -> int:
ans = abs(nums[0] - k)
s = {nums[0]}
ans = inf
s = set()
for x in nums:
s = {x & y for y in s} | {x}
s = {x | y for y in s} | {x}
ans = min(ans, min(abs(y - k) for y in s))
return ans
```
Expand All @@ -301,13 +301,12 @@ class Solution:
```java
class Solution {
public int minimumDifference(int[] nums, int k) {
int ans = Math.abs(nums[0] - k);
int ans = Integer.MAX_VALUE;
Set<Integer> pre = new HashSet<>();
pre.add(nums[0]);
for (int x : nums) {
Set<Integer> cur = new HashSet<>();
for (int y : pre) {
cur.add(x & y);
cur.add(x | y);
}
cur.add(x);
for (int y : cur) {
Expand All @@ -326,14 +325,13 @@ class Solution {
class Solution {
public:
int minimumDifference(vector<int>& nums, int k) {
int ans = abs(nums[0] - k);
int ans = INT_MAX;
unordered_set<int> pre;
pre.insert(nums[0]);
for (int x : nums) {
unordered_set<int> cur;
cur.insert(x);
for (int y : pre) {
cur.insert(x & y);
cur.insert(x | y);
}
for (int y : cur) {
ans = min(ans, abs(y - k));
Expand All @@ -349,41 +347,33 @@ public:
```go
func minimumDifference(nums []int, k int) int {
ans := abs(nums[0] - k)
pre := map[int]bool{nums[0]: true}
ans := math.MaxInt32
pre := map[int]bool{}
for _, x := range nums {
cur := map[int]bool{x: true}
for y := range pre {
cur[x&y] = true
cur[x|y] = true
}
for y := range cur {
ans = min(ans, abs(y-k))
ans = min(ans, max(y-k, k-y))
}
pre = cur
}
return ans
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
```

#### TypeScript

```ts
function minimumDifference(nums: number[], k: number): number {
let ans = Math.abs(nums[0] - k);
let ans = Infinity;
let pre = new Set<number>();
pre.add(nums[0]);
for (const x of nums) {
const cur = new Set<number>();
cur.add(x);
for (const y of pre) {
cur.add(x & y);
cur.add(x | y);
}
for (const y of cur) {
ans = Math.min(ans, Math.abs(y - k));
Expand Down
Loading

0 comments on commit b0f757b

Please sign in to comment.