Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 49dc10e

Browse files
✨feat: Add 467 & 691
1 parent 029813a commit 49dc10e

File tree

6 files changed

+233
-2
lines changed

6 files changed

+233
-2
lines changed

‎Index/二进制枚举.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
| 题目 | 题解 | 难度 | 推荐指数 |
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
3+
| [691. 贴纸拼词](https://leetcode.cn/problems/stickers-to-spell-word/) | [LeetCode 题解链接](https://leetcode.cn/problems/stickers-to-spell-word/solution/by-ac_oier-5vv3/) | 困难 | 🤩🤩🤩🤩 |
34
| [1239. 串联字符串的最大长度](https://leetcode-cn.com/problems/maximum-length-of-a-concatenated-string-with-unique-characters/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-length-of-a-concatenated-string-with-unique-characters/solution/gong-shui-san-xie-yi-ti-san-jie-jian-zhi-nfeb/) | 中等 | 🤩🤩🤩 |
45
| [1601. 最多可达成的换楼请求数目](https://leetcode-cn.com/problems/maximum-number-of-achievable-transfer-requests/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-number-of-achievable-transfer-requests/solution/gong-shui-san-xie-er-jin-zhi-mei-ju-by-a-enef/) | 中等 | 🤩🤩🤩🤩 |
56
| [2044. 统计按位或能得到最大值的子集数目](https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/solution/by-ac_oier-dos6/) | 困难 | 🤩🤩🤩🤩 |

‎Index/树状数组.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| [327. 区间和的个数](https://leetcode.cn/problems/count-of-range-sum/) | [LeetCode 题解链接](https://leetcode.cn/problems/count-of-range-sum/solution/by-ac_oier-b36o/) | 困难 | 🤩🤩🤩🤩🤩 |
55
| [406. 根据身高重建队列](https://leetcode.cn/problems/queue-reconstruction-by-height/) | [LeetCode 题解链接](https://leetcode.cn/problems/queue-reconstruction-by-height/solution/by-ac_oier-fda2/) | 中等 | 🤩🤩🤩 |
66
| [354. 俄罗斯套娃信封问题](https://leetcode-cn.com/problems/russian-doll-envelopes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/russian-doll-envelopes/solution/zui-chang-shang-sheng-zi-xu-lie-bian-xin-6s8d/) | 困难 | 🤩🤩🤩 |
7+
| [467. 环绕字符串中唯一的子字符串](https://leetcode.cn/problems/unique-substrings-in-wraparound-string/) | [LeetCode 题解链接](https://leetcode.cn/problems/unique-substrings-in-wraparound-string/solution/by-ac_oier-qteu/) | 中等 | 🤩🤩🤩🤩 |
78
| [673. 最长递增子序列的个数](https://leetcode-cn.com/problems/number-of-longest-increasing-subsequence/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-longest-increasing-subsequence/solution/gong-shui-san-xie-lis-de-fang-an-shu-wen-obuz/) | 中等 | 🤩🤩🤩🤩 |
89
| [1310. 子数组异或查询](https://leetcode-cn.com/problems/xor-queries-of-a-subarray/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/xor-queries-of-a-subarray/solution/gong-shui-san-xie-yi-ti-shuang-jie-shu-z-rcgu/) | 中等 | 🤩🤩🤩🤩 |
910
| [1893. 检查是否区域内所有整数都被覆盖](https://leetcode-cn.com/problems/check-if-all-the-integers-in-a-range-are-covered/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/check-if-all-the-integers-in-a-range-are-covered/solution/gong-shui-san-xie-yi-ti-shuang-jie-mo-ni-j83x/) | 简单 | 🤩🤩🤩🤩 |

‎Index/状压 DP.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
| 题目 | 题解 | 难度 | 推荐指数 |
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
33
| [526. 优美的排列](https://leetcode-cn.com/problems/beautiful-arrangement/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/beautiful-arrangement/solution/gong-shui-san-xie-xiang-jie-liang-chong-vgsia/) | 中等 | 🤩🤩🤩🤩🤩 |
4+
| [691. 贴纸拼词](https://leetcode.cn/problems/stickers-to-spell-word/) | [LeetCode 题解链接](https://leetcode.cn/problems/stickers-to-spell-word/solution/by-ac_oier-5vv3/) | 困难 | 🤩🤩🤩🤩 |
45
| [847. 访问所有节点的最短路径](https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes/solution/gong-shui-san-xie-yi-ti-shuang-jie-bfs-z-6p2k/) | 困难 | 🤩🤩🤩🤩🤩 |
56
| [1994. 好子集的数目](https://leetcode-cn.com/problems/the-number-of-good-subsets/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/the-number-of-good-subsets/solution/gong-shui-san-xie-zhuang-ya-dp-yun-yong-gz4w5/) | 困难 | 🤩🤩🤩🤩 |
67
| [2044. 统计按位或能得到最大值的子集数目](https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/solution/by-ac_oier-dos6/) | 困难 | 🤩🤩🤩🤩 |

‎Index/线性 DP.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| [213. 打家劫舍 II](https://leetcode-cn.com/problems/house-robber-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/house-robber-ii/solution/gong-shui-san-xie-ru-he-jiang-xin-xian-z-zf0w/) | 中等 | 🤩🤩🤩 |
1010
| [338. 比特位计数](https://leetcode-cn.com/problems/counting-bits/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/counting-bits/solution/po-su-jie-fa-dong-tai-gui-hua-jie-fa-by-vvail/) | 简单 | 🤩🤩🤩 |
1111
| [403. 青蛙过河](https://leetcode-cn.com/problems/frog-jump/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/frog-jump/solution/gong-shui-san-xie-yi-ti-duo-jie-jiang-di-74fw/) | 困难 | 🤩🤩🤩 |
12+
| [467. 环绕字符串中唯一的子字符串](https://leetcode.cn/problems/unique-substrings-in-wraparound-string/) | [LeetCode 题解链接](https://leetcode.cn/problems/unique-substrings-in-wraparound-string/solution/by-ac_oier-qteu/) | 中等 | 🤩🤩🤩🤩 |
1213
| [576. 出界的路径数](https://leetcode-cn.com/problems/out-of-boundary-paths/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/out-of-boundary-paths/solution/gong-shui-san-xie-yi-ti-shuang-jie-ji-yi-asrz/) | 中等 | 🤩🤩🤩🤩 |
1314
| [639. 解码方法 II](https://leetcode-cn.com/problems/decode-ways-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/decode-ways-ii/solution/gong-shui-san-xie-fen-qing-kuang-tao-lun-902h/) | 困难 | 🤩🤩🤩🤩 |
1415
| [650. 只有两个键的键盘](https://leetcode-cn.com/problems/2-keys-keyboard/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/2-keys-keyboard/solution/gong-shui-san-xie-yi-ti-san-jie-dong-tai-f035/) | 中等 | 🤩🤩🤩🤩 |
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[467. 环绕字符串中唯一的子字符串](https://leetcode.cn/problems/can-i-win/solution/by-ac_oier-0ed9/)** ,难度为 **中等**
4+
5+
Tag : 「线性 DP」、「树状数组」
6+
7+
8+
9+
把字符串 `s` 看作是 `"abcdefghijklmnopqrstuvwxyz"` 的无限环绕字符串,所以 `s` 看起来是这样的:
10+
11+
`"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...."` .
12+
13+
现在给定另一个字符串 `p` 。返回 `s` 中 唯一 的 `p` 的 非空子串 的数量 。
14+
15+
示例 1:
16+
```
17+
输入: p = "a"
18+
19+
输出: 1
20+
21+
解释: 字符串 s 中只有一个"a"子字符。
22+
```
23+
示例 2:
24+
```
25+
输入: p = "cac"
26+
27+
输出: 2
28+
29+
解释: 字符串 s 中的字符串"cac"只有两个子串"a"、"c"。.
30+
```
31+
示例 3:
32+
```
33+
输入: p = "zab"
34+
35+
输出: 6
36+
37+
解释: 在字符串 s 中有六个子串"z"、"a"、"b"、"za"、"ab"、"zab"。
38+
```
39+
40+
提示:
41+
* 1ドル <= p.length <= 10^5$
42+
* `p` 由小写英文字母构成
43+
44+
---
45+
46+
### 线性 DP + 树状数组 + 同字符最大长度计数
47+
48+
> 早上起来没睡醒,第一反应是用「线性 DP + 树状数组」来做,估了一下时间复杂度没问题就写了。
49+
该做法可能有一定的思维难度,因此可能不是这道中等题的标准解法。
50+
51+
**定义 $f[i]$ 为以 $s[i]$ 为结尾的最大有效子串的长度。**
52+
53+
从该状态定义容易得到如下的状态转移方程:
54+
55+
* 存在 $s[i - 1]$ 并且 $s[i]$ 能够接在 $s[i - 1]$ 后面(除了 $s[i]$ 为 $s[i - 1]$ 的下一字母以外,还特别包括 $s[i - 1] = z$ 同时 $s[i] = a$ 的情况),则我们有 $f[i] = f[i - 1] + 1$;
56+
* 不存在 $s[i - 1]$ 或者 $s[i]$ 不能接在 $s[i - 1]$ 后面,则有 $f[i] = 1,ドル含义为 $s[i]$ 只能自身组成子串。
57+
58+
**与此同时,我们知道当结尾元素固定,子串长度固定,对应子串唯一确定。**
59+
60+
当不考虑子串重复问题时,若 $f[i] = k,ドル则以 $s[i]$ 为结尾的有效子串数量为 $k$ 个(对应以 $s[i]$ 为结尾,长度范围为 $[1, k]$ 的子数组)。
61+
62+
但实际上,我们不能统计相同的子串,因此我们需要考虑该如何去重。
63+
64+
不失一般性地,假设我们当前处理到字符串 `p` 中的第 $i$ 位,以 $s[i]$ 为结尾的最大子串长度为 $f[i]$:
65+
66+
* 此前如果 **出现过** 以 $s[i]$ 为结尾,长度「大于等于」$f[i]$ 的子串的话,那么以 $s[i]$ 为结尾长度为 $f[i]$ 的子串必然已被统计,需要跳过。因此我们可以使用一个长度为 26ドル$ 的数组 `max`,记录以每个字符 $s[i]$ 结尾的,出现过的最大子串长度为多少(当 `max[s[i]] >= f[i]` 时,跳过计数);
67+
* 此前如果 **出现过** 以 $s[i]$ 为结尾,长度「小于」$f[i]$ 的子串的话,我们也不能直接统计累加 $f[i]$ 到答案上,这会导致那些以 $s[i]$ 为结尾,长度小于 $f[i]$ 的子串被重复计数,此时我们 **需要知道在以 $s[i]$ 为结尾,长度为 $[1, f[i]]$ 范围内还有多少个子串尚未被统计**,这可以使用「树状数组」解决:在 $[1, f[i]]$ 中总个数为 $a = f[i],ドル使用树状数组维护在 $[1, f[i]]$ 中已被统计的数的个数 $b,ドル那么 $cnt = a - b$ 即是本次可增加的计数,计数完成后我们还需要在树状数组中的 $f[i]$ 位置增加 $cnt,ドル确保下次查询相同字符结尾长度不小于 $f[i]$ 的已覆盖子串数量时不会出错。
68+
69+
至此,我们通过「树状数组」+「记录同字符最大长度」的方式来分别解决「长度比 $f[i]$ 小」和「长度比 $f[i]$ 大」的重复子串统计问题。
70+
71+
代码:
72+
```Java
73+
class Solution {
74+
int N = 100010;
75+
int[][] trs = new int[26][N];
76+
int[] f = new int[N], max = new int[26];
77+
int n, ans;
78+
int lowbit(int x) {
79+
return x & -x;
80+
}
81+
void add(int[] tr, int x, int v) {
82+
for (int i = x; i <= n + 1; i += lowbit(i)) tr[i] += v;
83+
}
84+
int query(int[] tr, int x) {
85+
int ans = 0;
86+
for (int i = x; i > 0; i -= lowbit(i)) ans += tr[i];
87+
return ans;
88+
}
89+
public int findSubstringInWraproundString(String _p) {
90+
char[] cs = _p.toCharArray();
91+
n = cs.length;
92+
for (int i = 0; i < n; i++) {
93+
int c = cs[i] - 'a';
94+
if (i == 0) {
95+
f[i] = 1;
96+
} else {
97+
int p = cs[i - 1] - 'a';
98+
if ((c == 0 && p == 25) || p + 1 == c) f[i] = f[i - 1] + 1;
99+
else f[i] = 1;
100+
}
101+
if (max[c] >= f[i]) continue;
102+
int cnt = f[i] - query(trs[c], f[i]);
103+
if (cnt == 0) continue;
104+
ans += cnt;
105+
add(trs[c], f[i], cnt);
106+
max[c] = f[i];
107+
}
108+
return ans;
109+
}
110+
}
111+
```
112+
* 时间复杂度:$O(n\log{n})$
113+
* 空间复杂度:$O(C \times N),ドル其中 $C = 26$ 为字符串 `p` 的字符集大小
114+
115+
---
116+
117+
### 最后
118+
119+
这是我们「刷穿 LeetCode」系列文章的第 `No.467` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
120+
121+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
122+
123+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
124+
125+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
126+

‎LeetCode/691-700/691. 贴纸拼词(困难).md‎

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
这是 LeetCode 上的 **[691. 贴纸拼词](https://leetcode.cn/problems/stickers-to-spell-word/solution/by-ac_oier-5vv3/)** ,难度为 **困难**
44

5-
Tag : 「记忆化搜索」、「DFS」、「状态压缩」、「爆搜」
5+
Tag : 「记忆化搜索」、「DFS」、「状压 DP」、「爆搜」、「动态规划」、「二进制枚举」、「状态压缩
66

77

88

@@ -43,7 +43,7 @@ Tag : 「记忆化搜索」、「DFS」、「状态压缩」、「爆搜」
4343

4444
---
4545

46-
### DFS + 记忆化搜索
46+
### 动态规划(记忆化搜索)
4747

4848
为了方便,我们记 $ss = stickers,ドル$t = target,ドル其中 $t$ 的长度为 $n$。
4949

@@ -94,6 +94,107 @@ class Solution {
9494

9595
---
9696

97+
### 动态规划
98+
99+
定义 $f[state]$ 为当前 $t$ 的凑成情况为 $state$ 时,使用的最少贴纸数量。
100+
101+
对应的我们有 $f[0] = 0,ドル代表当 $t$ 的任何一位都不被凑成时,所需要的最小贴纸数量为 0ドル$。
102+
103+
每次我们尝试使用有效的状态 $s$($f[s]$ 不为 `INF` 为有效状态)来更新新状态 $ns,ドル状态转移过程与解法一类似,每次尝试使用任意的 $ss[i]$ 来得到新的 $ns$。
104+
105+
代码:
106+
```Java
107+
class Solution {
108+
static int N = 15, INF = 20;
109+
static int[] f = new int[1 << N];
110+
public int minStickers(String[] ss, String t) {
111+
int n = ss.length, m = t.length(), mask = 1 << m;
112+
Arrays.fill(f, INF);
113+
f[0] = 0;
114+
for (int s = 0; s < mask; s++) {
115+
if (f[s] == INF) continue;
116+
for (String str : ss) {
117+
int ns = s, len = str.length();
118+
for (int i = 0; i < len; i++) {
119+
int c = str.charAt(i) - 'a';
120+
for (int j = 0; j < m; j++) {
121+
if (t.charAt(j) - 'a' == c && (((ns >> j) & 1) == 0)) {
122+
ns |= (1 << j);
123+
break;
124+
}
125+
}
126+
}
127+
f[ns] = Math.min(f[ns], f[s] + 1);
128+
}
129+
}
130+
return f[mask - 1] == INF ? -1 : f[mask - 1];
131+
}
132+
}
133+
```
134+
* 时间复杂度:令 $n$ 和 $m$ 分别代表字符串 `t` 的长度和数组 `ss` 的长度。共有 2ドル^n$ 个状态,单次状态的计算复杂度为 $$O(\sum_{i = 0}^{m - 1}ss[i].length \times n)$$。整体复杂度为 $$O(2^n \times \sum_{i = 0}^{m - 1}ss[i].length \times n)$$
135+
* 空间复杂度:$O(2^n)$
136+
137+
---
138+
139+
### 预处理优化
140+
141+
在解法一和解法二的状态转移过程中,我们每次都尝试枚举所有的 $ss[i]$ 来将 $s$ 更新为 $ns$。
142+
143+
实际上,可以有效填充 $t$ 中尚未被占用字符的 $ss[i]$ 可能只是少数,因此我们可以先预处理每个 $ss[i]$ 到底能够提供那些字符。
144+
145+
在将状态 $s$ 更新为 $ns$ 时,我们只枚举那些有效的 $ss[i]$。
146+
147+
代码:
148+
```Java
149+
class Solution {
150+
static int N = 15, INF = 20;
151+
static int[] f = new int[1 << N];
152+
public int minStickers(String[] ss, String t) {
153+
int n = ss.length, m = t.length(), mask = 1 << m;
154+
Map<Integer, List<Integer>> map = new HashMap<>();
155+
for (int i = 0; i < n; i++) {
156+
String str = ss[i];
157+
for (char c : str.toCharArray()) {
158+
int d = c - 'a';
159+
List<Integer> list = map.getOrDefault(d, new ArrayList<>());
160+
if (list.size() == 0 || list.get(list.size() - 1) != i) list.add(i);
161+
map.put(d, list);
162+
}
163+
}
164+
Arrays.fill(f, INF);
165+
f[0] = 0;
166+
for (int s = 0; s < mask; s++) {
167+
if (f[s] == INF) continue;
168+
int loc = -1;
169+
for (int i = 0; i < m && loc == -1; i++) {
170+
if (((s >> i) & 1) == 0) loc = i;
171+
}
172+
if (loc == -1) continue;
173+
List<Integer> list = map.getOrDefault(t.charAt(loc) - 'a', new ArrayList<>());
174+
for (int i = 0; i < list.size(); i++) {
175+
String str = ss[list.get(i)];
176+
int ns = s, len = str.length();
177+
for (int j = 0; j < len; j++) {
178+
char c = str.charAt(j);
179+
for (int k = 0; k < m; k++) {
180+
if (t.charAt(k) == c && (((ns >> k) & 1) == 0)) {
181+
ns |= (1 << k);
182+
break;
183+
}
184+
}
185+
}
186+
f[ns] = Math.min(f[ns], f[s] + 1);
187+
}
188+
}
189+
return f[mask - 1] == INF ? -1 : f[mask - 1];
190+
}
191+
}
192+
```
193+
* 时间复杂度:令 $n$ 和 $m$ 分别代表字符串 `t` 的长度和数组 `ss` 的长度。共有 2ドル^n$ 个状态,单次状态的计算复杂度为 $$O(\sum_{i = 0}^{m - 1}ss[i].length \times n)$$。整体复杂度为 $$O(2^n \times \sum_{i = 0}^{m - 1}ss[i].length \times n)$$
194+
* 空间复杂度:$O(2^n)$
195+
196+
---
197+
97198
### 最后
98199

99200
这是我们「刷穿 LeetCode」系列文章的第 `No.691` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /