Skip to content

feat: update solutions to lc problems: No.3171,3209 #3227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading