From 1ac72d66aa118ca01d37c90cc865ccdd6dbbb9d9 Mon Sep 17 00:00:00 2001 From: binacs Date: Sat, 3 Aug 2024 16:46:22 +0800 Subject: [PATCH] add: weekly 394 --- basic/basic-sort.md | 82 +++---- basic/sort.md | 203 +++++++++++++----- ds/bst.md | 47 ++++ ds/linked-list.md | 2 +- graph/shortest-path.md | 99 ++++++++- graph/topo.md | 2 +- lang/algorithm.md | 2 +- math/combinatorics/cantor.md | 133 ++++++++++++ .../inclusion-exclusion-principle.md | 2 +- misc/josephus.md | 47 ++++ misc/random.md | 1 - topic/bf-improve.md | 162 ++++++++++++++ 12 files changed, 680 insertions(+), 102 deletions(-) diff --git a/basic/basic-sort.md b/basic/basic-sort.md index 001fa65..6ab1b74 100644 --- a/basic/basic-sort.md +++ b/basic/basic-sort.md @@ -451,53 +451,32 @@ inline void radix_sort(unsigned A[], int len) > [!TIP] **思路** > -> +> BFPRT
详细代码 -##### **C++** +##### **C++ 标准** ```cpp class Solution { public: - int partition(vector& nums, int l, int r) { - int pivot = nums[l]; - while (l < r) { - while (r > l && nums[r] >= pivot) -- r ; - nums[l] = nums[r]; - while (r > l && nums[l] <= pivot) ++ l ; - nums[r] = nums[l]; - } - nums[l] = pivot; - return l; - } - int findKthLargest(vector& nums, int k) { - int l = 0, r = nums.size() - 1; - int tar = r - k + 1; - while (l < r) { - int idx = partition(nums, l, r); - if (idx < tar) l = idx + 1; - else r = idx; - } - return l < nums.size() ? nums[l] : -1; - } -}; - -// yxc version 1 -class Solution { -public: - int quick_sort(vector& nums, int l, int r, int k) { - if (l == r) return nums[k]; - int x = nums[l], i = l - 1, j = r + 1; + // k 保持不变 持续缩小范围 + int quick_sort(vector & nums, int l, int r, int k) { + if (l >= r) // ATTENTION + return nums[k]; + int i = l - 1, j = r + 1, x = nums[l + r >> 1]; while (i < j) { - do i ++ ; while (nums[i] > x); + do i ++ ; while (nums[i] > x); // ATTENTION > do j -- ; while (nums[j] < x); - if (i < j) swap(nums[i], nums[j]); + if (i < j) + swap(nums[i], nums[j]); } - if (k <= j) return quick_sort(nums, l, j, k); - else return quick_sort(nums, j + 1, r, k); + if (k <= j) + return quick_sort(nums, l, j, k); + else + return quick_sort(nums, j + 1, r, k); } int findKthLargest(vector& nums, int k) { @@ -505,7 +484,6 @@ public: } }; -// yxc version 2 class Solution { public: int quick_sort(vector & nums, int l, int r, int k) { @@ -515,7 +493,8 @@ public: while (i < j) { do i ++ ; while (nums[i] > x); do j -- ; while (nums[j] < x); - if (i < j) swap(nums[i], nums[j]); + if (i < j) + swap(nums[i], nums[j]); } if (j - l + 1 >= k) return quick_sort(nums, l, j, k); @@ -529,6 +508,35 @@ public: }; ``` +##### **C++ 废弃** + +```cpp +class Solution { +public: + int partition(vector& nums, int l, int r) { + int pivot = nums[l]; + while (l < r) { + while (r > l && nums[r] >= pivot) -- r ; + nums[l] = nums[r]; + while (r > l && nums[l] <= pivot) ++ l ; + nums[r] = nums[l]; + } + nums[l] = pivot; + return l; + } + int findKthLargest(vector& nums, int k) { + int l = 0, r = nums.size() - 1; + int tar = r - k + 1; + while (l < r) { + int idx = partition(nums, l, r); + if (idx < tar) l = idx + 1; + else r = idx; + } + return l < nums.size() ? nums[l] : -1; + } +}; +``` + ##### **Python** ```python diff --git a/basic/sort.md b/basic/sort.md index 2e73838..6367eda 100644 --- a/basic/sort.md +++ b/basic/sort.md @@ -24,6 +24,8 @@ > [!TIP] **思路** > > 标准实现 +> +> 【如果有局部数组和全局数组同名,会导致操作对象出问题,最好是把局部数组穿进去 heapify】
详细代码 @@ -34,26 +36,25 @@ ```cpp class Solution { public: - vector ns; - - void quick_sort(int l, int r) { + void quick_sort(vector & nums, int l, int r) { if (l >= r) return; - int i = l - 1, j = r + 1, x = ns[l + r >> 1]; + int i = l - 1, j = r + 1, x = nums[l + r >> 1]; while (i < j) { - do i ++ ; while (ns[i] < x); - do j -- ; while (ns[j] > x); + do i ++ ; while (nums[i] < x); + do j -- ; while (nums[j] > x); if (i < j) - swap(ns[i], ns[j]); + swap(nums[i], nums[j]); } - quick_sort(l, j); - quick_sort(j + 1, r); + // ATTENTION 只能用 j + // Luogu https://www.luogu.com.cn/problem/P1177 + quick_sort(nums, l, j); + quick_sort(nums, j + 1, r); } vector sortArray(vector& nums) { - this->ns = nums; - quick_sort(0, ns.size() - 1); - return ns; + quick_sort(nums, 0, nums.size() - 1); + return nums; } }; ``` @@ -64,37 +65,33 @@ public: class Solution { public: const static int N = 5e4 + 10; - - vector ns; + int tmp[N]; - void merge_sort(int l, int r) { + void merge_sort(vector & nums, int l, int r) { if (l >= r) return; int mid = l + r >> 1; - merge_sort(l, mid), merge_sort(mid + 1, r); - - int k = 0, i = l, j = mid + 1; - while (i <= mid && j <= r) { - if (ns[i] <= ns[j]) - tmp[k ++ ] = ns[i ++ ]; + merge_sort(nums, l, mid), merge_sort(nums, mid + 1, r); + int i = l, j = mid + 1, k = 0; + while (i <= mid && j <= r) + if (nums[i] <= nums[j]) + tmp[k ++ ] = nums[i ++ ]; else - tmp[k ++ ] = ns[j ++ ]; - } - + tmp[k ++ ] = nums[j ++ ]; + while (i <= mid) - tmp[k ++ ] = ns[i ++ ]; - while (j <= r) - tmp[k ++ ] = ns[j ++ ]; + tmp[k ++ ] = nums[i ++ ]; + while (j <= mid) + tmp[k ++ ] = nums[j ++ ]; - for (int i = l, j = 0; i <= r; ++ i, ++ j ) - ns[i] = tmp[j]; + for (int i = l, j = 0; j < k; ++ i , ++ j ) + nums[i] = tmp[j]; } vector sortArray(vector& nums) { - this->ns = nums; - merge_sort(0, ns.size() - 1); - return ns; + merge_sort(nums, 0, nums.size() - 1); + return nums; } }; ``` @@ -104,11 +101,11 @@ public: ```cpp class Solution { public: - vector ns; - int cnt; + int n; - void heapify(int u) { + void heapify(vector & nums, int u) { int t = u; + int ls = u << 1, rs = u << 1 | 1; // 1. 下标需要恢复 -1 // 2. 不需要从小到大输出 反而需要从大到小整理(大的放末尾并收缩) 故使用大顶堆 /* @@ -117,19 +114,18 @@ public: if (u * 2 + 1 <= cnt && ns[u * 2 + 1 - 1] > ns[t - 1]) t = u * 2 + 1; */ - int lc = u << 1, rc = u << 1 | 1; - if (lc <= cnt && ns[lc - 1] > ns[t - 1]) - t = lc; - if (rc <= cnt && ns[rc - 1] > ns[t - 1]) - t = rc; - if (u != t) { - swap(ns[u - 1], ns[t - 1]); - heapify(t); + if (ls <= n && nums[ls - 1] > nums[t - 1]) + t = ls; + if (rs <= n && nums[rs - 1] > nums[t - 1]) + t = rs; + if (t != u) { + swap(nums[u - 1], nums[t - 1]); + heapify(nums, t); } } - void heap_sort(int n) { - this->cnt = n; + vector sortArray(vector& nums) { + this->n = nums.size(); // 1. 建堆 // 数组下标从0开始 故使用 (n-2)/2 与 i>=0 @@ -137,21 +133,16 @@ public: // // 实际上,下标从 1 起始会更好写 for (int i = n / 2; i; -- i ) - heapify(i); + heapify(nums, i); // 2. 排序 // 当前堆顶已经是最大值 考虑挨个swap - for (int i = n; i >= 2; -- i ) { - swap(ns[i - 1], ns[1 - 1]); - cnt -- ; - heapify(1); + for ( ; n; ) { + swap(nums[1 - 1], nums[n - 1]); + n -- ; + heapify(nums, 1); } - } - - vector sortArray(vector& nums) { - this->ns = nums; - heap_sort(ns.size()); - return ns; + return nums; } }; ``` @@ -163,15 +154,46 @@ class Solution { public: void bubbleSort(vector & nums) { // 1. p 定位待放置的元素 - // 2. i 从头到位扫描并迁移元素 + // 2. i 从头到尾扫描并 [迁移元素] + // + // => p 右侧是已排序区间 左侧待排序区间 for (int p = nums.size() - 1; p; -- p ) for (int i = 1; i <= p; ++ i ) if (nums[i - 1] > nums[i]) swap(nums[i - 1], nums[i]); } + void selectionSort(vector & nums) { + // 1. p 定位待放置的元素 + // 2. i 从头到尾扫描并 [选择最大元素位置] + // + // => p 右侧是已排序区间 左侧待排序区间 + for (int p = nums.size() - 1; p; -- p ) { + int max_idx = 0; + for (int i = 1; i <= p; ++ i ) + if (nums[i] > nums[max_idx]) + max_idx = i; + swap(nums[p], nums[max_idx]); + } + } + + void insertionSort(vector & nums) { + // 1. p 定位待【定位】的元素 + // 2. i 从头扫到尾 找到待定位元素应当放置的位置 + // + // => p 左侧是已排序区间 右侧待排序区间 + for (int p = 1; p < nums.size(); ++ p ) { + // 不断将当前元素往前挪 + for (int i = p; i; -- i ) + if (nums[i] < nums[i - 1]) + swap(nums[i], nums[i - 1]); + else + break; + } + } + vector sortArray(vector& nums) { - bubbleSort(nums); + insertionSort(nums); return nums; } }; @@ -235,4 +257,67 @@ public:
-* * * \ No newline at end of file +* * * + +> [!NOTE] **[LeetCode 215. 数组中的第K个最大元素](https://leetcode.cn/problems/kth-largest-element-in-an-array/)** +> +> 题意: TODO + +> [!TIP] **思路** +> +> BFPRT + +
+详细代码 + + +##### **C++ 标准** + +```cpp +class Solution { +public: + // k 保持不变 持续缩小范围 + int quick_sort(vector & nums, int l, int r, int k) { + if (l >= r) // ATTENTION + return nums[k]; + int i = l - 1, j = r + 1, x = nums[l + r >> 1]; + while (i < j) { + do i ++ ; while (nums[i] > x); // ATTENTION > + do j -- ; while (nums[j] < x); + if (i < j) + swap(nums[i], nums[j]); + } + if (k <= j) + return quick_sort(nums, l, j, k); + else + return quick_sort(nums, j + 1, r, k); + } + + int findKthLargest(vector& nums, int k) { + return quick_sort(nums, 0, nums.size() - 1, k - 1); + } +}; + +class Solution { +public: + int quick_sort(vector & nums, int l, int r, int k) { + if (l >= r) + return nums[l]; + int i = l - 1, j = r + 1, x = nums[l + r >> 1]; + while (i < j) { + do i ++ ; while (nums[i] > x); + do j -- ; while (nums[j] < x); + if (i < j) + swap(nums[i], nums[j]); + } + if (j - l + 1 >= k) + return quick_sort(nums, l, j, k); + else + return quick_sort(nums, j + 1, r, k - (j - l + 1)); + } + + int findKthLargest(vector& nums, int k) { + return quick_sort(nums, 0, nums.size() - 1, k); + } +}; +``` diff --git a/ds/bst.md b/ds/bst.md index e1786e1..9f4d89e 100644 --- a/ds/bst.md +++ b/ds/bst.md @@ -836,6 +836,53 @@ class Solution: return isBST(root) +``` + + +
+ +
+ +* * * + +> [!NOTE] **[LeetCode LCR 152. 验证二叉搜索树的后序遍历序列](https://leetcode.cn/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/description/)** +> +> 题意: TODO + +> [!TIP] **思路** +> +> 单调栈解法 二叉树后序遍历性质 + +
+详细代码 + + +##### **C++** + +```cpp +class Solution { +public: + bool verifyPostorder(vector& postorder) { + int pre = INT_MAX, n = postorder.size(); + stack st; + for (int i = n - 1; i >= 0; -- i ) { + if (postorder[i] > pre) + return false; + while (st.size() && st.top() > postorder[i]) { + pre = st.top(); + st.pop(); + } + st.push(postorder[i]); + } + return true; + } +}; +``` + +##### **Python** + +```python + ``` diff --git a/ds/linked-list.md b/ds/linked-list.md index c7c585a..dd09e32 100644 --- a/ds/linked-list.md +++ b/ds/linked-list.md @@ -1645,7 +1645,7 @@ public: fast = fast->next->next; slow = slow->next; if (fast == slow) { - // fast 比 slow 多走了一个环的长度 + // fast 比 slow 多走了 x 个环的长度 ret = head; while (ret != slow) { ret = ret->next; diff --git a/graph/shortest-path.md b/graph/shortest-path.md index ef659f6..515f3c5 100644 --- a/graph/shortest-path.md +++ b/graph/shortest-path.md @@ -5,6 +5,8 @@ > 在函数参数重传了 `int sth[]` 数组的不要在数组内部 `memset(sth, 0x3f, sizeof sth)` > > 因为 `sizeof` 拿到的不是真实大小 +> +> => 如果是 int 用 `sizeof 4 * N` ## 定义 @@ -1044,6 +1046,100 @@ public: * * * +> [!NOTE] **[LeetCode 3123. 最短路径中的边](https://leetcode.cn/problems/find-edges-in-shortest-paths/)** +> +> 题意: TODO + +> [!TIP] **思路** +> +> 标准求【最短路径边】的算法 +> +> - 两次 dijkstra 校验每条边左右两侧到起始点的距离和 +> +> - 一次 dijkstra + 逆序路径长度判断 (较麻烦 略) +> +> `sizeof 4 * N` + +
+详细代码 + + +##### **C++** + +```cpp +class Solution { +public: + using PII = pair; + const static int N = 5e4 + 10, M = 1e5 + 10, INF = 0x3f3f3f3f; + + int h[N], e[M], w[M], ne[M], idx; + void init() { + memset(h, -1, sizeof h); + idx = 0; + } + void add(int a, int b, int c) { + e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; + } + + int d1[N], d2[N]; + bool st[N]; + void dijkstra(int dist[], int s) { + memset(dist, 0x3f, sizeof 4 * N); + memset(st, 0, sizeof st); + priority_queue, greater> heap; + dist[s] = 0; heap.push({0, s}); + + while (heap.size()) { + auto [d, u] = heap.top(); heap.pop(); + if (st[u]) + continue; + st[u] = true; + + for (int i = h[u]; ~i; i = ne[i]) { + int j = e[i], c = w[i]; + if (dist[j] > d + c) + heap.push({dist[j] = d + c, j}); + } + } + } + + vector findAnswer(int n, vector>& edges) { + init(); + for (auto & e : edges) { + int a = e[0], b = e[1], c = e[2]; + add(a, b, c), add(b, a, c); + } + + dijkstra(d1, 0); + dijkstra(d2, n - 1); + + int tot = d1[n - 1]; + vector res; + for (auto & e : edges) { + int a = e[0], b = e[1], c = e[2]; + if (d1[a] + d2[b] + c == tot || d1[b] + d2[a] + c == tot) + res.push_back(true); + else + res.push_back(false); + } + return res; + } +}; +``` + +##### **Python** + +```python + +``` + + +
+ +
+ +* * * + ### dijkstra 进阶 > [!NOTE] **[AcWing 920. 最优乘车](https://www.acwing.com/problem/content/922/)** @@ -3483,6 +3579,8 @@ if __name__ == '__main__': > [!TIP] **思路** > > 推导 二分 转化为负环判定 +> +> SPFA
详细代码 @@ -4779,7 +4877,6 @@ public: }; ``` - ##### **Python** ```python diff --git a/graph/topo.md b/graph/topo.md index d941184..3263c22 100644 --- a/graph/topo.md +++ b/graph/topo.md @@ -1542,7 +1542,7 @@ public: > [!TIP] **思路** > -> +> 可重集排列问题
详细代码 diff --git a/lang/algorithm.md b/lang/algorithm.md index 2cab375..1db6132 100644 --- a/lang/algorithm.md +++ b/lang/algorithm.md @@ -228,7 +228,7 @@ class Solution: > > 故原题可以转化为求原排列是初始(升序)排列的第几个排列 > -> 显然有 **康托展开** 或 **数位DP** ==> TODO 整理 +> 显然有 **康托逆展开** 或 **数位DP** ==> TODO 整理
详细代码 diff --git a/math/combinatorics/cantor.md b/math/combinatorics/cantor.md index e3fcb64..a1f76fd 100644 --- a/math/combinatorics/cantor.md +++ b/math/combinatorics/cantor.md @@ -116,6 +116,139 @@ public: }; ``` +##### **Python** + +```python + +``` + + +
+ +
+ +* * * + +> [!NOTE] **[LeetCode 1830. 使字符串有序的最少操作次数](https://leetcode.cn/problems/minimum-number-of-operations-to-make-string-sorted/)** [TAG] +> +> 题意: TODO + +> [!TIP] **思路** +> +> 逆序观察 操作的过程(与求下一个排列恰好是逆操作)恰好是全排列 +> +> 故原题可以转化为求原排列是初始(升序)排列的第几个排列 +> +> 显然有 **康托逆展开** 或 **数位DP** ==> TODO 整理 + +
+详细代码 + + +##### **C++ 康托展开** + +```cpp +// 康托展开 +class Solution { +public: + using LL = long long; + const int MOD = 1e9 + 7; + + LL quick_pow(LL a, LL b, LL m) { + LL res = 1; + a %= m; + while (b) { + if (b & 1) + res = res * a % m; + a = a * a % m; + b >>= 1; + } + return res; + } + + int makeStringSorted(string s) { + int n = s.size(); + LL fact = 1, dup = 1; + LL res = 0; + vector seen(26, 0); + for (int i = n - 1; i >= 0; -- i ) { + seen[s[i] - 'a'] ++ ; + dup = dup * seen[s[i] - 'a'] % MOD; + + LL rk = 0; + for (int j = 0; j < s[i] - 'a'; ++ j ) + rk += seen[j]; + + res = (res + rk * fact % MOD * quick_pow(dup, MOD - 2, MOD) % MOD) % MOD; + fact = fact * (n - i) % MOD; + } + return res; + } +}; +``` + +##### **C++ 数位DP** + +```cpp +// 数位DP +class Solution { +public: + using LL = long long; + const int MOD = 1e9 + 7; + const static int N = 3010; + + LL f[N], g[N]; + + LL qmi(LL a, int b) { + LL res = 1; + while (b) { + if (b & 1) + res = res * a % MOD; + a = a * a % MOD; + b >>= 1; + } + return res; + } + + // 重复排列问题 + int get(vector & cnt) { + int sum = 0; + for (int i = 0; i < 26; ++ i ) + sum += cnt[i]; + int res = f[sum]; + for (int i = 0; i < 26; ++ i ) + res = (LL)res * g[cnt[i]] % MOD; + return res; + } + + int makeStringSorted(string s) { + f[0] = g[0] = 1; + for (int i = 1; i <= s.size(); ++ i ) { + f[i] = f[i - 1] * i % MOD; + g[i] = qmi(f[i], MOD - 2); + } + + int res = 0; + vector cnt(26, 0); + for (auto c : s) + cnt[c - 'a'] ++ ; + for (auto c : s) { + int x = c - 'a'; + for (int i = 0; i < x; ++ i ) { + if (!cnt[i]) + continue; + cnt[i] -- ; + res = (res + get(cnt)) % MOD; + cnt[i] ++ ; + } + cnt[x] -- ; + } + return res; + } +}; +``` + + ##### **Python** ```python diff --git a/math/combinatorics/inclusion-exclusion-principle.md b/math/combinatorics/inclusion-exclusion-principle.md index 304f50e..17025d0 100644 --- a/math/combinatorics/inclusion-exclusion-principle.md +++ b/math/combinatorics/inclusion-exclusion-principle.md @@ -995,7 +995,7 @@ public: * * * -> [!NOTE] **[LeetCode 1782. 统计点对的数目]()** [TAG] +> [!NOTE] **[LeetCode 1782. 统计点对的数目](https://leetcode.cn/problems/count-pairs-of-nodes/)** [TAG] > > 题意: TODO diff --git a/misc/josephus.md b/misc/josephus.md index 86b4ed1..06ea5a9 100644 --- a/misc/josephus.md +++ b/misc/josephus.md @@ -84,6 +84,53 @@ $$ ## 习题 +> [!NOTE] **[LeetCode LCR 187. 破冰游戏](https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/)** +> +> 题意: TODO + +> [!TIP] **思路** +> +> 标准约瑟夫环 + +
+详细代码 + + +##### **C++** + +```cpp +// AcWing +class Solution { +public: + int lastRemaining(int n, int m) { + if (n == 1) + return 0; + return (lastRemaining(n - 1, m) + m)% n; + } + + int lastRemaining2(int n, int m){ + int res = 0; + // 最后一轮剩下2个人,所以从2开始反推 + for (int i = 2; i <= n; ++ i ) + res = (res + m) % i; + return res; + } +}; +``` + +##### **Python** + +```python + +``` + + +
+ +
+ +* * * + > [!NOTE] **[LeetCode 390. 消除游戏](https://leetcode.cn/problems/elimination-game/)** > > 题意: TODO diff --git a/misc/random.md b/misc/random.md index 7cc4102..63b6575 100644 --- a/misc/random.md +++ b/misc/random.md @@ -433,7 +433,6 @@ public: }; ``` - ##### **Python** ```python diff --git a/topic/bf-improve.md b/topic/bf-improve.md index ede55d1..ef6b818 100644 --- a/topic/bf-improve.md +++ b/topic/bf-improve.md @@ -1131,6 +1131,168 @@ public: * * * +> [!NOTE] **[LeetCode 1521. 找到最接近目标值的函数值](https://leetcode.cn/problems/find-a-value-of-a-mysterious-function-closest-to-target/)** [TAG] +> +> 题意: TODO + +> [!TIP] **思路** +> +> 可以部分参考 [898. 子数组按位或操作](https://leetcode.cn/problems/bitwise-ors-of-subarrays/) +> +> - 双指针 + 前缀和 +> +> - 动态维护 TODO clear => LogTrick +> +> - 模拟退火 TODO clear + +
+详细代码 + + +##### **C++ 双指针+前缀和** + +```cpp +class Solution { +public: + // 1e6 数据范围 则最多不超过 20 个不同的值 => 思考 + const static int N = 1e5 + 10, M = 20; + + int s[N][M]; // 逆序思维: 不记录有没有 1 而是记录某一位有没有 0 + + int get_sum(int l, int r) { + int res = 0; + for (int i = 0; i < M; ++ i ) + if (s[r][i] - s[l - 1][i] == 0) // 没有 0 存在 + res += 1 << i; + return res; + } + + int closestToTarget(vector& arr, int target) { + int n = arr.size(); + + memset(s, 0, sizeof s); + for (int i = 1; i <= n; ++ i ) + for (int j = 0; j < M; ++ j ) { + s[i][j] = s[i - 1][j]; + if (!(arr[i - 1] >> j & 1)) + s[i][j] ++ ; + } + + int res = INT_MAX; + for (int l = 1, r = 1; r <= n; ++ r ) { + while (l < r && abs(get_sum(l + 1, r)) <= target) + l ++ ; + res = min(res, abs(get_sum(l, r) - target)); + if (l < r) + res = min(res, abs(get_sum(l + 1, r) - target)); + } + return res; + } +}; +``` + +##### **C++ 动态维护** + +```cpp +class Solution { +public: + int closestToTarget(vector& arr, int target) { + int ans = abs(arr[0] - target); + vector valid = {arr[0]}; + for (int num : arr) { + vector validNew = {num}; + ans = min(ans, abs(num - target)); + for (int prev : valid) { + validNew.push_back(prev & num); + ans = min(ans, abs((prev & num) - target)); + } + validNew.erase(unique(validNew.begin(), validNew.end()), + validNew.end()); + valid = validNew; + } + return ans; + } +}; +``` + +##### **C++ 模拟退火** + +```cpp +class Solution { +public: + //通过预处理,快速求解arr[L..R]的与值 + int pre[100001][20] = {0}; + + int get(int L, int R, int target) { + int val = 0; + for (int i = 0, bit = 1; i < 20; i++, bit <<= 1) + // 如果第 i 个bit 在 [L,R] 中全为 1,那么与值的该bit也必然为 1。 + if (pre[R][i] - pre[L - 1][i] == R - L + 1) { val |= bit; } + return abs(val - target); + } + + // 用模拟退火求解关于 L 的局部最优解 + int query(int L, int n, int target) { + int dir[2] = {-1, 1}; // 两个方向 + int step = 1000; // 初始步长 + int now = L; // R 的起始位置 + int best = 100000000; // 局部最优解 + + while (step > 0) { + int Lpos = now + step * dir[0]; + if (Lpos < L) Lpos = L; + int Rpos = now + step * dir[1]; + if (Rpos > n) Rpos = n; + // 向左右两个方向各走一步,求值 + int ldis = get(L, Lpos, target); + int rdis = get(L, Rpos, target); + int pbest = best; + + //更新位置及最优解 + if (ldis < best) { + now = Lpos; + best = ldis; + } + if (rdis < best) { + now = Rpos; + best = rdis; + } + + //如果没有找到更优解,那就缩小步长 + if (pbest == best) { step /= 2; } + } + return best; + } + + int closestToTarget(vector& arr, int target) { + int anw = 100000000; + + //统计前 i 个数字中,第 j 个bit 为 1 的数量。 + for (int i = 0; i < arr.size(); i++) + for (int j = 0, bit = 1; j < 20; j++, bit <<= 1) + pre[i + 1][j] = pre[i][j] + ((bit & arr[i]) ? 1 : 0); + + for (int i = 1; i <= arr.size(); i++) + anw = min(anw, query(i, arr.size(), target)); + + return anw; + } +}; +``` + +##### **Python** + +```python + +``` + + +
+ +
+ +* * * + ### 双指针 > [!NOTE] **[LeetCode 1521. 找到最接近目标值的函数值](https://leetcode.cn/problems/find-a-value-of-a-mysterious-function-closest-to-target/)** [TAG]