Skip to content

Commit 99b45c6

Browse files
committed
✨feat: update 828
1 parent d4fa39a commit 99b45c6

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

Index/线性 DP.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
| [678. 有效的括号字符串](https://leetcode-cn.com/problems/valid-parenthesis-string/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/valid-parenthesis-string/solution/gong-shui-san-xie-yi-ti-shuang-jie-dong-801rq/) | 中等 | 🤩🤩🤩🤩🤩 |
1717
| [688. 骑士在棋盘上的概率](https://leetcode-cn.com/problems/knight-probability-in-chessboard/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/knight-probability-in-chessboard/solution/gong-shui-san-xie-jian-dan-qu-jian-dp-yu-st8l/) | 中等 | 🤩🤩🤩🤩🤩 |
1818
| [741. 摘樱桃](https://leetcode.cn/problems/cherry-pickup/) | [LeetCode 题解链接](https://leetcode.cn/problems/cherry-pickup/solution/by-ac_oier-pz7i/) | 困难 | 🤩🤩🤩🤩 |
19+
| [828. 统计子串中的唯一字符](https://leetcode.cn/problems/count-unique-characters-of-all-substrings-of-a-given-string/) | [LeetCode 题解链接](https://leetcode.cn/problems/count-unique-characters-of-all-substrings-of-a-given-string/solution/by-ac_oier-922k/) | 困难 | 🤩🤩🤩🤩 |
1920
| [978. 最长湍流子数组](https://leetcode-cn.com/problems/longest-turbulent-subarray/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-turbulent-subarray/solution/xiang-jie-dong-tai-gui-hua-ru-he-cai-dp-3spgj/) | 中等 | 🤩🤩🤩🤩 |
2021
| [1137. 第 N 个泰波那契数](https://leetcode-cn.com/problems/n-th-tribonacci-number/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/n-th-tribonacci-number/solution/gong-shui-san-xie-yi-ti-si-jie-die-dai-d-m1ie/) | 简单 | 🤩🤩🤩🤩 |
2122
| [1220. 统计元音字母序列的数目](https://leetcode-cn.com/problems/count-vowels-permutation/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-vowels-permutation/solution/gong-shui-san-xie-yi-ti-shuang-jie-xian-n8f4o/) | 困难 | 🤩🤩🤩🤩 |

LeetCode/821-830/828. 统计子串中的唯一字符(困难).md

+54-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
这是 LeetCode 上的 **[828. 统计子串中的唯一字符](https://leetcode.cn/problems/count-unique-characters-of-all-substrings-of-a-given-string/solution/by-ac_oier-922k/)** ,难度为 **困难**
44

5-
Tag : 「模拟」、「数学」
5+
Tag : 「模拟」、「数学」、「线性 DP」
66

77

88

@@ -110,6 +110,59 @@ function uniqueLetterString(s: string): number {
110110

111111
---
112112

113+
### 线性 DP
114+
115+
另外一个实现思路是利用「动态规划」思想。
116+
117+
定义 $f[i]$ 为考虑以 $s[i]$ 为结尾的所有子串中的唯一字符个数。
118+
119+
不失一般性考虑 $f[i]$ 该如何转移:以 $s[i]$ 为结尾的子串包括在所有以 $s[i - 1]$ 为结尾的子串结尾添加一个字符而来,以及 $s[i]$ 字符本身组成的新子串。
120+
121+
首先我们令 $f[i] = f[i - 1]$,同时使用 $b[x]$ 记录字符 $x$ 前一次出现的下标,使用 $a[x]$ 记录字符 $x$ 在上上次出现的下标,然后假设当前处理的字符为 $c = s[i]$,考虑 $s[i]$ 对 $f[i]$ 的影响(注意 $s[i]$ 始终为子串右端点):
122+
123+
* 在子串左端点下标范围在 $[b[c] + 1, i]$ 的子串中,$s[i]$ 必然只出现一次(满足唯一字符要求),即可增加 $i - b[c]$ 个唯一字符 $s[i]$;
124+
* 在子串左端点下标范围在 $[a[c] + 1, b[c]]$ 的子串中,原本位于 $b[c]$ 的字符在新子串中出现次数变为 $2$ 次(不再满足唯一字符要求),即需减少 $b[c] - a[c]$ 个唯一字符 $s[i]$。
125+
126+
综上,我们有状态转移方程:$f[i] = f[i - 1] + (i - b[s[i]]) - (b[s[i]] - a[s[i]])$
127+
128+
实现上,由于 $f[i]$ 只依赖于 $f[i - 1]$,因此我们真的无须创建动规数组,而只需要使用单个变量 `cur` 来记录当前处理到的 $f[i]$ 即可,累积所有的 $f[i]$ 即是答案。
129+
130+
Java 代码:
131+
```Java
132+
class Solution {
133+
public int uniqueLetterString(String s) {
134+
int n = s.length(), ans = 0, cur = 0;
135+
int[] a = new int[26], b = new int[26];
136+
Arrays.fill(a, -1); Arrays.fill(b, -1);
137+
for (int i = 0; i < n; i++) {
138+
int u = s.charAt(i) - 'A';
139+
cur += i - b[u] - (b[u] - a[u]);
140+
ans += cur;
141+
a[u] = b[u]; b[u] = i;
142+
}
143+
return ans;
144+
}
145+
}
146+
```
147+
TypeScript 代码:
148+
```TypeScript
149+
function uniqueLetterString(s: string): number {
150+
let n = s.length, ans = 0, cur = 0
151+
const a = new Array<number>(26).fill(-1), b = new Array<number>(26).fill(-1)
152+
for (let i = 0; i < n; i++) {
153+
const u = s.charCodeAt(i) - 65
154+
cur += i - b[u] - (b[u] - a[u])
155+
ans += cur
156+
a[u] = b[u]; b[u] = i
157+
}
158+
return ans
159+
};
160+
```
161+
* 时间复杂度:$O(n)$
162+
* 空间复杂度:$O(C)$,其中 $C = 26$ 为字符集大小
163+
164+
---
165+
113166
### 最后
114167

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

0 commit comments

Comments
 (0)