From 53402bd3e9d88cc214220c7606dcfa1b40246be6 Mon Sep 17 00:00:00 2001 From: AC_Oier Date: Sat, 23 Mar 2024 16:39:51 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8feat:=20add=201092=E3=80=811253?= =?UTF-8?q?=E3=80=811260=E3=80=811408=E3=80=811473=E3=80=811640=E3=80=8117?= =?UTF-8?q?43=E3=80=811759=E3=80=811802=E3=80=81236=E3=80=81481=E3=80=8154?= =?UTF-8?q?3=E3=80=81636=E3=80=81687=E3=80=81764=E3=80=81769=E3=80=81777?= =?UTF-8?q?=E3=80=81790=E3=80=81791=E3=80=81805=E3=80=81808=E3=80=81864?= =?UTF-8?q?=E3=80=81895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...10\345\233\260\351\232\276\357\274\211.md" | 87 +++++--- ...10\344\270\255\347\255\211\357\274\211.md" | 92 +++++++- ...10\347\256\200\345\215\225\357\274\211.md" | 37 +++- ...10\347\256\200\345\215\225\357\274\211.md" | 4 +- ...10\345\233\260\351\232\276\357\274\211.md" | 18 +- ...10\347\256\200\345\215\225\357\274\211.md" | 106 ++++++--- ...10\344\270\255\347\255\211\357\274\211.md" | 161 ++++++++++++-- ...10\344\270\255\347\255\211\357\274\211.md" | 55 +++-- ...10\344\270\255\347\255\211\357\274\211.md" | 209 +++++++++++++++++- ...10\344\270\255\347\255\211\357\274\211.md" | 104 ++++++++- ...10\344\270\255\347\255\211\357\274\211.md" | 186 +++++++++++++++- ...10\344\270\255\347\255\211\357\274\211.md" | 2 +- ...10\344\270\255\347\255\211\357\274\211.md" | 103 ++++++--- ...10\347\256\200\345\215\225\357\274\211.md" | 53 ++++- ...10\344\270\255\347\255\211\357\274\211.md" | 65 +++++- ...10\344\270\255\347\255\211\357\274\211.md" | 47 +++- ...10\344\270\255\347\255\211\357\274\211.md" | 45 ++++ ...10\344\270\255\347\255\211\357\274\211.md" | 82 +++++-- ...10\344\270\255\347\255\211\357\274\211.md" | 46 ++-- ...10\344\270\255\347\255\211\357\274\211.md" | 56 ++++- ...10\344\270\255\347\255\211\357\274\211.md" | 111 +++++++--- ...10\344\270\255\347\255\211\357\274\211.md" | 54 +++-- ...10\345\233\260\351\232\276\357\274\211.md" | 105 ++++++++- ...10\344\270\255\347\255\211\357\274\211.md" | 53 ++++- ...10\345\233\260\351\232\276\357\274\211.md" | 144 ++++++++---- ...10\345\233\260\351\232\276\357\274\211.md" | 59 +++-- README.md | 4 +- 27 files changed, 1766 insertions(+), 322 deletions(-) diff --git "a/LeetCode/1091-1100/1092. \346\234\200\347\237\255\345\205\254\345\205\261\350\266\205\345\272\217\345\210\227\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1091-1100/1092. \346\234\200\347\237\255\345\205\254\345\205\261\350\266\205\345\272\217\345\210\227\357\274\210\345\233\260\351\232\276\357\274\211.md" index 950ca18d..61ab1f71 100644 --- "a/LeetCode/1091-1100/1092. \346\234\200\347\237\255\345\205\254\345\205\261\350\266\205\345\272\217\345\210\227\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1091-1100/1092. \346\234\200\347\237\255\345\205\254\345\205\261\350\266\205\345\272\217\345\210\227\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -90,36 +90,39 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function shortestCommonSupersequence(s1: string, s2: string): string { - const n = s1.length, m = s2.length - s1 = " " + s1; s2 = " " + s2 - const f = new Array>() - for (let i = 0; i < n + 10; i++) f.push(new Array(m + 10).fill(0)) - for (let i = 1; i <= n; i++) { - for (let j = 1; j <= m; j++) { - if (s1[i] == s2[j]) f[i][j] = f[i - 1][j - 1] + 1 - else f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]) +C++ 代码: +```C++ +class Solution { +public: + string shortestCommonSupersequence(string str1, string str2) { + int n = str1.size(), m = str2.size(); + str1 = " " + str1; str2 = " " + str2; + vector> f(n + 10, vector(m + 10)); + for (int i = 1; i <= n; ++i) { + for (int j = 1; j <= m; ++j) { + if (str1[i] == str2[j]) + f[i][j] = f[i - 1][j - 1] + 1; + else + f[i][j] = max(f[i - 1][j], f[i][j - 1]); + } } - } - let ans = "" - let i = n, j = m - while (i > 0 || j > 0) { - if (i == 0) ans += s2[j--] - else if (j == 0) ans += s1[i--] - else { - if (s1[i] == s2[j]) { - ans += s1[i] - i--; j-- - } else if (f[i][j] == f[i - 1][j]) { - ans += s1[i--] - } else { - ans += s2[j--] + string res; + int i = n, j = m; + while (i > 0 || j > 0) { + if (i == 0) res += str2[j--]; + else if (j == 0) res += str1[i--]; + else { + if (str1[i] == str2[j]) { + res += str1[i]; + i--; j--; + } + else if (f[i][j] == f[i - 1][j]) res += str1[i--]; + else res += str2[j--]; } } + reverse(res.begin(), res.end()); + return res; } - return ans.split('').reverse().join('') }; ``` Python 代码: @@ -155,6 +158,38 @@ class Solution: j -= 1 return ans[::-1] ``` +TypeScript 代码: +```TypeScript +function shortestCommonSupersequence(s1: string, s2: string): string { + const n = s1.length, m = s2.length + s1 = " " + s1; s2 = " " + s2 + const f = new Array>() + for (let i = 0; i < n + 10; i++) f.push(new Array(m + 10).fill(0)) + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= m; j++) { + if (s1[i] == s2[j]) f[i][j] = f[i - 1][j - 1] + 1 + else f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]) + } + } + let ans = "" + let i = n, j = m + while (i > 0 || j > 0) { + if (i == 0) ans += s2[j--] + else if (j == 0) ans += s1[i--] + else { + if (s1[i] == s2[j]) { + ans += s1[i] + i--; j-- + } else if (f[i][j] == f[i - 1][j]) { + ans += s1[i--] + } else { + ans += s2[j--] + } + } + } + return ans.split('').reverse().join('') +}; +``` * 时间复杂度:`LCS` 复杂度为 $O(n \times m)$;构造答案复杂度为 $O(n \times m)$。整体复杂度为 $O(n \times m)$ * 空间复杂度:$O(n \times m)$ diff --git "a/LeetCode/1251-1260/1253. \351\207\215\346\236\204 2 \350\241\214\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1251-1260/1253. \351\207\215\346\236\204 2 \350\241\214\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\357\274\210\344\270\255\347\255\211\357\274\211.md" index 8eca5495..963c2226 100644 --- "a/LeetCode/1251-1260/1253. \351\207\215\346\236\204 2 \350\241\214\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1251-1260/1253. \351\207\215\346\236\204 2 \350\241\214\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -61,10 +61,11 @@ Tag : 「模拟」、「贪心」、「构造」 若处理完 `colsum` 后,两行剩余 $1$ 个数恰好均为 $0$,说明构造出了合法方案。 -容易证明:**不存在某个决策回合中,必须先填入剩余个数少的一方,才能顺利构造。**可用反证法进行证明,若存在某个回合必须填入剩余个数少的一方(假设该回合上填 `1` 下填 `0`),必然能够找到同为 $colsum[j] = 1$ 的回合进行交换,同时不影响合法性(上下行的总和不变,同时 $colsum[i] = colsum[j] = 1$)。 +容易证明:**不存在某个决策回合中,必须先填入剩余个数少的一方,才能顺利构造。** -代码: +可用反证法进行证明,若存在某个回合必须填入剩余个数少的一方(假设该回合上填 `1` 下填 `0`),必然能够找到同为 $colsum[j] = 1$ 的回合进行交换,同时不影响合法性(上下行的总和不变,同时 $colsum[i] = colsum[j] = 1$)。 +Java 代码: ```Java class Solution { public List> reconstructMatrix(int upper, int lower, int[] colsum) { @@ -95,6 +96,93 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector> reconstructMatrix(int upper, int lower, vector& colsum) { + int n = colsum.size(); + vector> ans; + vector a, b; + for (int i = 0; i < n; i++) { + int m = colsum[i]; + if (m == 0) { + a.push_back(0); b.push_back(0); + } else if (m == 2) { + upper--; lower--; + a.push_back(1); b.push_back(1); + } else { + if (upper >= lower) { + upper--; + a.push_back(1); b.push_back(0); + } else { + lower--; + a.push_back(0); b.push_back(1); + } + } + } + if (upper == 0 && lower == 0) { + ans.push_back(a); ans.push_back(b); + } + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def reconstructMatrix(self, upper: int, lower: int, colsum: List[int]) -> List[List[int]]: + n = len(colsum) + ans = [] + a, b = [], [] + for i in range(n): + m = colsum[i] + if m == 0: + a.append(0) + b.append(0) + elif m == 2: + upper, lower = upper - 1, lower - 1 + a.append(1) + b.append(1) + else: + a.append(1 if upper >= lower else 0) + b.append(0 if upper >= lower else 1) + if upper >= lower: upper -= 1 + else: lower -= 1 + if upper == lower == 0: + ans.append(a) + ans.append(b) + return ans +``` +TypeScript 代码: +```TypeScript +function reconstructMatrix(upper: number, lower: number, colsum: number[]): number[][] { + const n = colsum.length; + let ans: number[][] = []; + let a: number[] = [], b: number[] = []; + for (let i = 0; i < n; i++) { + const m = colsum[i]; + if (m === 0) { + a.push(0); b.push(0); + } else if (m === 2) { + upper--; lower--; + a.push(1); b.push(1); + } else { + if (upper >= lower) { + upper--; + a.push(1); b.push(0); + } else { + lower--; + a.push(0); b.push(1); + } + } + } + if (upper === 0 && lower === 0) { + ans.push(a); ans.push(b); + } + return ans; +}; +``` * 时间复杂度:$O(C \times n)$,其中 $C = 2$ 代表行数 * 空间复杂度:$O(C \times n)$ diff --git "a/LeetCode/1251-1260/1260. \344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273\357\274\210\347\256\200\345\215\225\357\274\211.md" "b/LeetCode/1251-1260/1260. \344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273\357\274\210\347\256\200\345\215\225\357\274\211.md" index f0045e97..b307c0d9 100644 --- "a/LeetCode/1251-1260/1260. \344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273\357\274\210\347\256\200\345\215\225\357\274\211.md" +++ "b/LeetCode/1251-1260/1260. \344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273\357\274\210\347\256\200\345\215\225\357\274\211.md" @@ -6,7 +6,9 @@ Tag : 「模拟」、「构造」 -给你一个 `m` 行 `n` 列的二维网格 `grid` 和一个整数 `k`。你需要将 `grid` 迁移 `k` 次。 +给你一个 `m` 行 `n` 列的二维网格 `grid` 和一个整数 `k`。 + +你需要将 `grid` 迁移 `k` 次。 每次「迁移」操作将会引发下述活动: @@ -75,6 +77,39 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector> shiftGrid(vector>& g, int k) { + int n = g.size(), m = g[0].size(); + vector> mat(n, vector(m)); + for(int i = 0; i < m; ++i) { + int tcol = (i + k) % m, trow = ((i + k) / m) % n, idx = 0; + while(idx != n) { + mat[trow++][tcol] = g[idx++][i]; + if(trow == n) trow = 0; + } + } + return mat; + } +}; +``` +Python 代码: +```Python +class Solution: + def shiftGrid(self, g: List[List[int]], k: int) -> List[List[int]]: + n, m = len(g), len(g[0]) + mat = [[0]*m for _ in range(n)] + for i in range(m): + tcol = (i + k) % m + trow = ((i + k) // m) % n + idx = 0 + while idx != n: + mat[trow][tcol] = g[idx][i] + trow, idx = (trow + 1) % n, idx + 1 + return mat +``` TypeScript 代码: ```TypeScript function shiftGrid(g: number[][], k: number): number[][] { diff --git "a/LeetCode/1401-1410/1408. \346\225\260\347\273\204\344\270\255\347\232\204\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\357\274\210\347\256\200\345\215\225\357\274\211.md" "b/LeetCode/1401-1410/1408. \346\225\260\347\273\204\344\270\255\347\232\204\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\357\274\210\347\256\200\345\215\225\357\274\211.md" index 2ca380a3..488292fd 100644 --- "a/LeetCode/1401-1410/1408. \346\225\260\347\273\204\344\270\255\347\232\204\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\357\274\210\347\256\200\345\215\225\357\274\211.md" +++ "b/LeetCode/1401-1410/1408. \346\225\260\347\273\204\344\270\255\347\232\204\345\255\227\347\254\246\344\270\262\345\214\271\351\205\215\357\274\210\347\256\200\345\215\225\357\274\211.md" @@ -6,7 +6,9 @@ Tag : 「模拟」 -给你一个字符串数组 `words`,数组中的每个字符串都可以看作是一个单词。请你按 任意 顺序返回 `words` 中是其他单词的子字符串的所有单词。 +给你一个字符串数组 `words`,数组中的每个字符串都可以看作是一个单词。 + +请你按任意顺序返回 `words` 中是其他单词的子字符串的所有单词。 如果你可以删除 `words[j]` 最左侧和/或最右侧的若干字符得到 `word[i]`,那么字符串 `words[i]` 就是 `words[j]` 的一个子字符串。 diff --git "a/LeetCode/1471-1480/1473. \347\262\211\345\210\267\346\210\277\345\255\220 III\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1471-1480/1473. \347\262\211\345\210\267\346\210\277\345\255\220 III\357\274\210\345\233\260\351\232\276\357\274\211.md" index 9ee3f5f4..d55cb147 100644 --- "a/LeetCode/1471-1480/1473. \347\262\211\345\210\267\346\210\277\345\255\220 III\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1471-1480/1473. \347\262\211\345\210\267\346\210\277\345\255\220 III\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -83,16 +83,20 @@ Tag : 「动态规划」、「序列 DP」 同时根据「第 $i$ 间房子的颜色 $j$」与「第 $i - 1$ 间房子的颜色 $p$」是否相同,会决定第 $i$ 间房子是否形成一个新的分区。这同样需要进行分情况讨论。 整理后的转移方程为: - $$ f[i][j][k]=\begin{cases} + $$ + f[i][j][k]=\begin{cases} min(f[i - 1][j][k], f[i - 1][p][k - 1]) &j == houses[i], p != j\\ INF & j != houses[i] - \end{cases}$$ + \end{cases} + $$ * 第 $i$ 间房子尚未被上色,即 $houses[i] == 0$,此时房子可以被粉刷成任意颜色。不会有无效状态的情况。 同样,根据「第 $i$ 间房子的颜色 $j$」与「第 $i - 1$ 间房子的颜色 $p$」是否相同,会决定第 $i$ 间房子是否形成一个新的分区。 转移方程为: - $$ f[i][j][k] = min(f[i - 1][j][k], f[i - 1][p][k - 1]) + cost[i][j - 1], p != j $$ + $$ + f[i][j][k] = min(f[i - 1][j][k], f[i - 1][p][k - 1]) + cost[i][j - 1], p != j + $$ 一些编码细节: @@ -167,8 +171,8 @@ class Solution { } } ``` -* 时间复杂度:共有 $m * n * t$ 个状态需要被转移,每次转移需要枚举「所依赖的状态」的颜色,复杂度为 $O(n)$。整体复杂度为 $O(m * n^2 * t)$ -* 空间复杂度:$O(m * n * t)$ +* 时间复杂度:共有 $m \times n \times t$ 个状态需要被转移,每次转移需要枚举「所依赖的状态」的颜色,复杂度为 $O(n)$。整体复杂度为 $O(m \times n^2 \times t)$ +* 空间复杂度:$O(m \times n \times t)$ --- @@ -280,8 +284,8 @@ class Solution { } } ``` -* 时间复杂度:共有 $m * n * t$ 个状态需要被转移,每次转移需要枚举「所依赖的状态」的颜色,复杂度为 $O(n)$。整体复杂度为 $O(m * n^2 * t)$ -* 空间复杂度:$O(m * n * t)$ +* 时间复杂度:共有 $m \times n \times t$ 个状态需要被转移,每次转移需要枚举「所依赖的状态」的颜色,复杂度为 $O(n)$。整体复杂度为 $O(m \times n^2 \times t)$ +* 空间复杂度:$O(m \times n \times t)$ --- diff --git "a/LeetCode/1631-1640/1640. \350\203\275\345\220\246\350\277\236\346\216\245\345\275\242\346\210\220\346\225\260\347\273\204\357\274\210\347\256\200\345\215\225\357\274\211.md" "b/LeetCode/1631-1640/1640. \350\203\275\345\220\246\350\277\236\346\216\245\345\275\242\346\210\220\346\225\260\347\273\204\357\274\210\347\256\200\345\215\225\357\274\211.md" index eebb93a6..b2b2a639 100644 --- "a/LeetCode/1631-1640/1640. \350\203\275\345\220\246\350\277\236\346\216\245\345\275\242\346\210\220\346\225\260\347\273\204\357\274\210\347\256\200\345\215\225\357\274\211.md" +++ "b/LeetCode/1631-1640/1640. \350\203\275\345\220\246\350\277\236\346\216\245\345\275\242\346\210\220\346\225\260\347\273\204\357\274\210\347\256\200\345\215\225\357\274\211.md" @@ -6,7 +6,13 @@ Tag : 「排序」、「二分」、「哈希表」、「模拟」 -给你一个整数数组 `arr` ,数组中的每个整数 互不相同 。另有一个由整数数组构成的数组 `pieces`,其中的整数也 互不相同 。请你以 任意顺序 连接 `pieces` 中的数组以形成 `arr` 。但是,不允许 对每个数组 `pieces[i]` 中的整数重新排序。 +给你一个整数数组 `arr` ,数组中的每个整数 互不相同 。 + +另有一个由整数数组构成的数组 `pieces`,其中的整数也互不相同。 + +请你以任意顺序连接 `pieces` 中的数组以形成 `arr` 。 + +但是,不允许对每个数组 `pieces[i]` 中的整数重新排序。 如果可以连接 `pieces` 中的数组形成 `arr` ,返回 `true` ;否则,返回 `false` 。 @@ -79,24 +85,27 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function canFormArray(arr: number[], pieces: number[][]): boolean { - const n = arr.length, m = pieces.length - pieces.sort((a,b)=>a[0]-b[0]) - for (let i = 0; i < n; ) { - let l = 0, r = m - 1 - while (l < r) { - const mid = l + r + 1 >> 1 - if (pieces[mid][0] <= arr[i]) l = mid - else r = mid - 1 +C++ 代码: +```C++ +class Solution { +public: + bool canFormArray(vector& arr, vector>& pieces) { + int n = arr.size(), m = pieces.size(); + sort(pieces.begin(), pieces.end()); + for (int i = 0; i < n; ) { + int l = 0, r = m - 1; + while (l < r) { + int mid = l + r + 1 >> 1; + if (pieces[mid][0] <= arr[i]) l = mid; + else r = mid - 1; + } + int len = pieces[r].size(), idx = 0; + while (idx < len && pieces[r][idx] == arr[i + idx]) idx++; + if (idx == len) i += len; + else return false; } - let len = pieces[r].length, idx = 0 - while (idx < len && pieces[r][idx] == arr[i + idx]) idx++ - if (idx == len) i += len - else return false + return true; } - return true }; ``` Python 代码: @@ -123,6 +132,26 @@ class Solution: return False return True ``` +TypeScript 代码: +```TypeScript +function canFormArray(arr: number[], pieces: number[][]): boolean { + const n = arr.length, m = pieces.length + pieces.sort((a,b)=>a[0]-b[0]) + for (let i = 0; i < n; ) { + let l = 0, r = m - 1 + while (l < r) { + const mid = l + r + 1 >> 1 + if (pieces[mid][0] <= arr[i]) l = mid + else r = mid - 1 + } + let len = pieces[r].length, idx = 0 + while (idx < len && pieces[r][idx] == arr[i + idx]) idx++ + if (idx == len) i += len + else return false + } + return true +}; +``` * 时间复杂度:排序复杂度为 $O(m\log{m})$;构造的复杂度为 $O(n\log{m})$。整体复杂度为 $O(m\log{m} + n\log{m})$ * 空间复杂度:$O(\log{m})$ @@ -150,19 +179,23 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function canFormArray(arr: number[], pieces: number[][]): boolean { - const n = arr.length, m = pieces.length - const hash = new Array(110).fill(0) - for (let i = 0; i < m; i++) hash[pieces[i][0]] = i - for (let i = 0; i < n; ) { - let cur = pieces[hash[arr[i]]], sz = cur.length, idx = 0 - while (idx < sz && cur[idx] == arr[i + idx]) idx++ - if (idx == sz) i += sz - else return false +C++ 代码: +```C++ +class Solution { +public: + bool canFormArray(vector& arr, vector>& pieces) { + int n = arr.size(), m = pieces.size(); + vector hash(110); + for (int i = 0; i < m; i++) hash[pieces[i][0]] = i; + for (int i = 0; i < n; ) { + vector cur = pieces[hash[arr[i]]]; + int len = cur.size(), idx = 0; + while (idx < len && cur[idx] == arr[i + idx]) idx++; + if (idx == len) i += len; + else return false; + } + return true; } - return true }; ``` Python 代码: @@ -185,6 +218,21 @@ class Solution: return False return True ``` +TypeScript 代码: +```TypeScript +function canFormArray(arr: number[], pieces: number[][]): boolean { + const n = arr.length, m = pieces.length + const hash = new Array(110).fill(0) + for (let i = 0; i < m; i++) hash[pieces[i][0]] = i + for (let i = 0; i < n; ) { + let cur = pieces[hash[arr[i]]], sz = cur.length, idx = 0 + while (idx < sz && cur[idx] == arr[i + idx]) idx++ + if (idx == sz) i += sz + else return false + } + return true +}; +``` * 时间复杂度:$O(n + m)$ * 空间复杂度:$O(C)$,其中 $C = 110$ 为两数组的值域大小 diff --git "a/LeetCode/1741-1750/1743. \344\273\216\347\233\270\351\202\273\345\205\203\347\264\240\345\257\271\350\277\230\345\216\237\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1741-1750/1743. \344\273\216\347\233\270\351\202\273\345\205\203\347\264\240\345\257\271\350\277\230\345\216\237\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" index 3aee7270..a7ce1cda 100644 --- "a/LeetCode/1741-1750/1743. \344\273\216\347\233\270\351\202\273\345\205\203\347\264\240\345\257\271\350\277\230\345\216\237\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1741-1750/1743. \344\273\216\347\233\270\351\202\273\345\205\203\347\264\240\345\257\271\350\277\230\345\216\237\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,13 +6,13 @@ Tag : 「哈希表」、「双指针」、「模拟」 -存在一个由 `n` 个不同元素组成的整数数组 `nums` ,但你已经记不清具体内容。好在你还记得 `nums` 中的每一对相邻元素。 +存在一个由 `n` 个不同元素组成的整数数组 `nums` ,但你已经记不清具体内容,好在你还记得 `nums` 中的每一对相邻元素。 给你一个二维整数数组 `adjacentPairs` ,大小为 `n - 1` ,其中每个 $adjacentPairs[i] = [u_i, v_i]$ 表示元素 $u_i$ 和 $v_i$ 在 `nums` 中相邻。 -题目数据保证所有由元素 `nums[i]` 和 `nums[i+1]` 组成的相邻元素对都存在于 `adjacentPairs` 中,存在形式可能是 `[nums[i], nums[i+1]]` ,也可能是 `[nums[i+1], nums[i]]` 。这些相邻元素对可以 按任意顺序 出现。 +题目数据保证所有由元素 `nums[i]` 和 `nums[i+1]` 组成的相邻元素对都存在于 `adjacentPairs` 中,存在形式可能是 `[nums[i], nums[i+1]]` ,也可能是 `[nums[i+1], nums[i]]` 。这些相邻元素对可以「按任意顺序」出现。 -返回 原始数组 `nums` 。如果存在多种解答,返回 其中任意一个 即可。 +返回原始数组 `nums` 。如果存在多种解答,返回其中任意一个即可。 示例 1: ``` @@ -57,16 +57,14 @@ Tag : 「哈希表」、「双指针」、「模拟」 因此我们可以使用「哈希表」对 $nums$ 中出现的数值进行计数,找到“出现一次”的数值作为 $ans$ 数值的首位,然后根据给定的相邻关系进行「单向构造」,为了方便找到某个数其相邻的数是哪些,我们还需要再开一个「哈希表」记录相邻关系。 -![image.png](https://pic.leetcode-cn.com/1627174782-ZZmRKQ-image.png) - -代码: +Java 代码: ```Java class Solution { - public int[] restoreArray(int[][] aps) { - int m = aps.length, n = m + 1; + public int[] restoreArray(int[][] adjacentPairs) { + int m = adjacentPairs.length, n = m + 1; Map cnts = new HashMap<>(); Map> map = new HashMap<>(); - for (int[] ap : aps) { + for (int[] ap : adjacentPairs) { int a = ap[0], b = ap[1]; cnts.put(a, cnts.getOrDefault(a, 0) + 1); cnts.put(b, cnts.getOrDefault(b, 0) + 1); @@ -98,6 +96,97 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector restoreArray(vector>& adjacentPairs) { + unordered_map cnts; + unordered_map> map; + for(auto& pair : adjacentPairs){ + int a = pair[0], b = pair[1]; + cnts[a]++, cnts[b]++; + map[a].push_back(b); + map[b].push_back(a); + } + int start; + for(auto& i : cnts) { + if(i.second == 1){ + start = i.first; + break; + } + } + int n = adjacentPairs.size() + 1; + vector ans(n); + ans[0] = start; + ans[1] = map[start][0]; + for(int i = 2; i < n; i++){ + int x = ans[i - 1]; + for(int j : map[x]) + if(j != ans[i-2]) ans[i] = j; + } + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def restoreArray(self, adjacentPairs: List[List[int]]) -> List[int]: + cnts = defaultdict(int) + map = defaultdict(list) + for ap in adjacentPairs: + a, b = ap[0], ap[1] + cnts[a] += 1 + cnts[b] += 1 + map[a].append(b) + map[b].append(a) + start = next(i for i in cnts if cnts[i] == 1) + n = len(adjacentPairs) + 1 + ans = [0] * n + ans[0] = start + ans[1] = map[start][0] + for i in range(2, n): + x = ans[i - 1] + for j in map[x]: + if j != ans[i - 2]: + ans[i] = j + return ans +``` +TypeScript 代码: +```TypeScript +function restoreArray(adjacentPairs: number[][]): number[] { + const cnts: {[key: number]: number} = {}; + const map: {[key: number]: number[]} = {}; + for(let pair of adjacentPairs){ + let a: number = pair[0], b: number = pair[1]; + cnts[a] = !cnts[a] ? 1 : cnts[a] + 1; + cnts[b] = !cnts[b] ? 1 : cnts[b] + 1; + if(!map[a]) map[a] = []; + if(!map[b]) map[b] = []; + map[a].push(b); + map[b].push(a); + } + let start: number; + for(let key in cnts){ + if(cnts[key] == 1){ + start = Number(key); + break; + } + } + const n: number = adjacentPairs.length + 1; + const ans: number[] = Array(n).fill(0); + ans[0] = start; + ans[1] = map[start][0]; + for(let i = 2; i> map = new HashMap<>(); - for (int[] ap : aps) { + for (int[] ap : adjacentPairs) { int a = ap[0], b = ap[1]; List alist = map.getOrDefault(a, new ArrayList<>()); alist.add(b); @@ -137,7 +224,7 @@ class Solution { map.put(b, blist); } int l = N / 2, r = l + 1; - int std = aps[0][0]; + int std = adjacentPairs[0][0]; List list = map.get(std); q[l--] = std; q[r++] = list.get(0); @@ -165,6 +252,48 @@ class Solution { } } ``` +C++ 代码: +```C++ +#define N 1000010 +class Solution { +public: + vector restoreArray(vector>& adjacentPairs) { + int m = adjacentPairs.size(), n = m + 1; + unordered_map> map; + for(auto& pair : adjacentPairs){ + int a = pair[0], b = pair[1]; + map[a].push_back(b); + map[b].push_back(a); + } + int l = N / 2, r = l + 1; + int s = adjacentPairs[0][0]; + vector q(N, 0); + q[l--] = s; + q[r++] = map[s][0]; + if (map[s].size() > 1) q[l--] = map[s][1]; + while ((r - 1) - (l + 1) + 1 < n){ + vector list = map[q[l + 1]]; + int j = l; + for(auto& i : list){ + if(i != q[l + 2]) q[j--] = i; + } + l = j; + + list = map[q[r - 1]]; + j = r; + for(auto& i : list){ + if(i != q[r - 2]) q[j++] = i; + } + r = j; + } + vector ans(n); + for(int i = l + 1, idx = 0; idx < n; ++i, ++idx){ + ans[idx] = q[i]; + } + return ans; + } +}; +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/1751-1760/1759. \347\273\237\350\256\241\345\220\214\346\236\204\345\255\220\345\255\227\347\254\246\344\270\262\347\232\204\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1751-1760/1759. \347\273\237\350\256\241\345\220\214\346\236\204\345\255\220\345\255\227\347\254\246\344\270\262\347\232\204\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" index e8069575..a99b6ff4 100644 --- "a/LeetCode/1751-1760/1759. \347\273\237\350\256\241\345\220\214\346\236\204\345\255\220\345\255\227\347\254\246\344\270\262\347\232\204\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1751-1760/1759. \347\273\237\350\256\241\345\220\214\346\236\204\345\255\220\345\255\227\347\254\246\344\270\262\347\232\204\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,11 +6,13 @@ Tag : 「双指针」、「数学」 -给你一个字符串 `s`,返回 `s` 中 同构子字符串 的数目。由于答案可能很大,只需返回对 $10^9 + 7$ 取余 后的结果。 +给你一个字符串 `s`,返回 `s` 中 同构子字符串 的数目。 -同构字符串 的定义为:如果一个字符串中的所有字符都相同,那么该字符串就是同构字符串。 +由于答案可能很大,只需返回对 $10^9 + 7$ 取余 后的结果。 -子字符串 是字符串中的一个连续字符序列。 +同构字符串的定义为:如果一个字符串中的所有字符都相同,那么该字符串就是同构字符串。 + +子字符串是字符串中的一个连续字符序列。 示例 1: ``` @@ -76,23 +78,27 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function countHomogenous(s: string): number { - let n = s.length, mod = 1e9+7, ans = 0 - for (let i = 0; i < n; ) { - let j = i - while (j < n && s.charAt(j) == s.charAt(i)) j++ - const cnt = j - i - ans += (1 + cnt) * cnt / 2 - ans %= mod - i = j +C++ 代码: +```C++ +class Solution { +public: + int countHomogenous(string s) { + int n = s.size(), MOD = 1e9+7; + long ans = 0; + for (int i = 0; i < n; ) { + int j = i; + while (j < n && s[j] == s[i]) j++; + long cnt = j - i; + ans += (1 + cnt) * cnt / 2; + ans %= MOD; + i = j; + } + return (int) ans; } - return ans -} +}; ``` Python3 代码: -```Python3 +```Python class Solution: def countHomogenous(self, s: str) -> int: n, mod, i, ans = len(s), 1e9+7, 0, 0 @@ -106,6 +112,21 @@ class Solution: i = j return int(ans) ``` +TypeScript 代码: +```TypeScript +function countHomogenous(s: string): number { + let n = s.length, mod = 1e9+7, ans = 0 + for (let i = 0; i < n; ) { + let j = i + while (j < n && s.charAt(j) == s.charAt(i)) j++ + const cnt = j - i + ans += (1 + cnt) * cnt / 2 + ans %= mod + i = j + } + return ans +} +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(1)$ diff --git "a/LeetCode/1791-1800/1797. \350\256\276\350\256\241\344\270\200\344\270\252\351\252\214\350\257\201\347\263\273\347\273\237\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1791-1800/1797. \350\256\276\350\256\241\344\270\200\344\270\252\351\252\214\350\257\201\347\263\273\347\273\237\357\274\210\344\270\255\347\255\211\357\274\211.md" index 63e9e54f..96a28ca5 100644 --- "a/LeetCode/1791-1800/1797. \350\256\276\350\256\241\344\270\200\344\270\252\351\252\214\350\257\201\347\263\273\347\273\237\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1791-1800/1797. \350\256\276\350\256\241\344\270\200\344\270\252\351\252\214\350\257\201\347\263\273\347\273\237\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,16 +6,25 @@ Tag : 「链表」、「哈希表」 -你需要设计一个包含验证码的验证系统。每一次验证中,用户会收到一个新的验证码,这个验证码在 `currentTime` 时刻之后 `timeToLive` 秒过期。如果验证码被更新了,那么它会在 `currentTime` (可能与之前的 `currentTime` 不同)时刻延长 `timeToLive` 秒。 +你需要设计一个包含验证码的验证系统。 + +每一次验证中,用户会收到一个新的验证码,这个验证码在 `ct` 时刻之后 `timeToLive` 秒过期。 + +如果验证码被更新了,那么它会在 `ct` (可能与之前的 `ct` 不同)时刻延长 `timeToLive` 秒。 请你实现 `AuthenticationManager` 类: * `AuthenticationManager(int timeToLive)` 构造 `AuthenticationManager` 并设置 `timeToLive` 参数。 -* `generate(string tokenId, int currentTime)` 给定 `tokenId`,在当前时间 `currentTime` 生成一个新的验证码。 -* `renew(string tokenId, int currentTime)` 将给定 `tokenId` 且 未过期 的验证码在 `currentTime` 时刻更新。如果给定 `tokenId` 对应的验证码不存在或已过期,请你忽略该操作,不会有任何更新操作发生。 -* `countUnexpiredTokens(int currentTime)` 请返回在给定 `currentTime` 时刻,未过期 的验证码数目。 -如果一个验证码在时刻 `t` 过期,且另一个操作恰好在时刻 `t` 发生(`renew` 或者 `countUnexpiredTokens` 操作),过期事件 优先于 其他操作。 +* `generate(string id, int ct)` 给定 `id`,在当前时间 `ct` 生成一个新的验证码。 + +* `renew(string id, int ct)` 将给定 `id` 且未过期的验证码在 `ct` 时刻更新。 + + 如果给定 `id` 对应的验证码不存在或已过期,请你忽略该操作,不会有任何更新操作发生。 + +* `countUnexpiredTokens(int ct)` 请返回在给定 `ct` 时刻,未过期的验证码数目。 + +如果一个验证码在时刻 `t` 过期,且另一个操作恰好在时刻 `t` 发生(`renew` 或者 `countUnexpiredTokens` 操作),过期事件优先于其他操作。 示例 1: ![](https://assets.leetcode.com/uploads/2021/02/25/copy-of-pc68_q2.png) @@ -42,9 +51,9 @@ authenticationManager.countUnexpiredTokens(15); // tokenId 为 "bbb" 的验证 * $1 <= timeToLive <= 10^8$ * $1 <= currentTime <= 10^8$ * $1 <= tokenId.length <= 5$ -* `tokenId` 只包含小写英文字母。 -* 所有 `generate` 函数的调用都会包含独一无二的 `tokenId` 值。 -* 所有函数调用中,`currentTime` 的值 严格递增 。 +* `id` 只包含小写英文字母。 +* 所有 `generate` 函数的调用都会包含独一无二的 `id` 值。 +* 所有函数调用中,`ct` 的值严格递增。 * 所有函数的调用次数总共不超过 `2000` 次。 --- @@ -53,7 +62,7 @@ authenticationManager.countUnexpiredTokens(15); // tokenId 为 "bbb" 的验证 数据范围只有 `20`,我们使用哈希表记录每个 `id` 的过期时间 `ct`,在每次查询时遍历整个哈希表来统计未过期的验证码数量。 -代码: +Java 代码: ```Java class AuthenticationManager { int d; @@ -77,6 +86,83 @@ class AuthenticationManager { } } ``` +C++ 代码: +```C++ +class AuthenticationManager { + int d; + unordered_map map; +public: + AuthenticationManager(int timeToLive) : d(timeToLive){} + void generate(string id, int ct) { + map[id] = ct + d; + } + void renew(string id, int ct) { + if (!map.count(id) || map[id] <= ct) return; + map[id] = ct + d; + } + int countUnexpiredTokens(int ct) { + int ans = 0; + for (auto it = map.begin(); it != map.end(); ++it) { + if (it->second > ct) ans++; + } + return ans; + } +}; +``` +Python 代码: +```Python +class AuthenticationManager: + def __init__(self, timeToLive): + self.d = timeToLive + self.map = {} + + def generate(self, id: str, ct: int) -> None: + self.map[id] = ct + self.d + + def renew(self, id: str, ct: int) -> None: + if id not in self.map or self.map[id] <= ct: + return + self.map[id] = ct + self.d + + def countUnexpiredTokens(self, ct: int) -> int: + ans = 0 + for id in self.map: + if self.map[id] > ct: + ans += 1 + return ans +``` +TypeScript 代码: +```TypeScript +class AuthenticationManager { + d: number; + map: { [id: string]: number } = {}; + + constructor(timeToLive: number) { + this.d = timeToLive; + } + + generate(id: string, ct: number): void { + this.map[id] = ct + this.d; + } + + renew(id: string, ct: number): void { + if (!this.map.hasOwnProperty(id) || this.map[id] <= ct) { + return; + } + this.map[id] = ct + this.d; + } + + countUnexpiredTokens(ct: number): number { + let ans = 0; + for (const id in this.map) { + if (this.map[id] > ct) { + ans++; + } + } + return ans; + } +} +``` * 时间复杂度:`generate` 操作和 `renew` 操作的复杂度为 $O(1)$;`countUnexpiredTokens` 操作的复杂度为 $O(n)$ * 空间复杂度:$O(n)$ @@ -98,8 +184,7 @@ class AuthenticationManager { 最后,我们像对其他链表题目一样,为了方便,引入 `he` 和 `ta` 的头尾链表哨兵节点以减少边界处理。 - -代码: +Java 代码: ```Java class AuthenticationManager { class Node { @@ -143,6 +228,108 @@ class AuthenticationManager { } } ``` +C++ 代码: +```C++ +class AuthenticationManager { + struct Node { + string id; + int t; + Node *prev, *next; + Node (string _id, int _t) : id(_id), t(_t), prev(nullptr), next(nullptr) {} + }; + int d; + Node *he, *ta; + unordered_map map; +public: + AuthenticationManager(int timeToLive) : d(timeToLive) { + he = new Node("", -1); + ta = new Node("", (int)1e9); + he->next = ta; + ta->prev = he; + } + void generate(string id, int ct) { + Node* node = new Node(id, ct + d); + node->prev = ta->prev; + node->next = ta; + ta->prev->next = node; + ta->prev = node; + map[id] = node; + } + void renew(string id, int ct) { + if (!map.count(id) || map[id]->t <= ct) return; + Node* node = map[id]; + node->prev->next = node->next; + node->next->prev = node->prev; + generate(id, ct); + } + int countUnexpiredTokens(int ct) { + int ans = 0; + Node* cur = ta->prev; + while (cur->t > ct && ++ans >= 0) cur = cur->prev; + he->next = cur->next; + cur->next->prev = he; + return ans; + } +}; +``` +TypeScript 代码: +```TypeScript +class Node { + id: string; + t: number; + prev: Node | null; + next: Node | null; + constructor(_id: string, _t: number) { + this.id = _id; + this.t = _t; + this.prev = null + this.next = null + } +} +class AuthenticationManager { + d: number; + he: Node; + ta: Node; + map: {[id: string]: Node}; + constructor(timeToLive: number) { + this.d = timeToLive; + this.he = new Node("", -1) + this.ta = new Node("", 1e9) + this.he.next = this.ta + this.ta.prev = this.he + this.map = {}; + } + + generate(id: string, ct: number) { + let node : Node = new Node(id, ct + this.d) ; + node.prev = this.ta.prev; + node.next = this.ta; + this.ta.prev!.next = node; + this.ta.prev = node; + this.map[id] = node; + } + + renew(id: string, ct: number) { + if (!this.map.hasOwnProperty(id) || this.map[id].t <= ct) { + return; + } + var node : Node = this.map[id]; + node.prev!.next = node.next; + node.next!.prev = node.prev; + this.generate(id, ct); + } + + countUnexpiredTokens(ct: number) { + let ans = 0; + let cur : Node = this.ta.prev!; + while (cur.t > ct && ++ans >= 0) + cur = cur.prev!; + this.he.next = cur.next; + cur.next!.prev = this.he; + return ans; + } +} +``` * 时间复杂度:`generate` 操作和 `renew` 操作的复杂度为 $O(1)$;`countUnexpiredTokens` 操作的复杂度为 $O(n)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/1801-1810/1802. \346\234\211\347\225\214\346\225\260\347\273\204\344\270\255\346\214\207\345\256\232\344\270\213\346\240\207\345\244\204\347\232\204\346\234\200\345\244\247\345\200\274\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1801-1810/1802. \346\234\211\347\225\214\346\225\260\347\273\204\344\270\255\346\214\207\345\256\232\344\270\213\346\240\207\345\244\204\347\232\204\346\234\200\345\244\247\345\200\274\357\274\210\344\270\255\347\255\211\357\274\211.md" index 79fb0d85..048f3ad9 100644 --- "a/LeetCode/1801-1810/1802. \346\234\211\347\225\214\346\225\260\347\273\204\344\270\255\346\214\207\345\256\232\344\270\213\346\240\207\345\244\204\347\232\204\346\234\200\345\244\247\345\200\274\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1801-1810/1802. \346\234\211\347\225\214\346\225\260\347\273\204\344\270\255\346\214\207\345\256\232\344\270\213\346\240\207\345\244\204\347\232\204\346\234\200\345\244\247\345\200\274\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,7 +6,9 @@ Tag : 「二分」、「数学」、「构造」、「贪心」、「模拟」 -给你三个正整数 `n`、`index` 和 `maxSum`。你需要构造一个同时满足下述所有条件的数组 `nums`(下标 从 `0` 开始 计数): +给你三个正整数 `n`、`index` 和 `maxSum`。 + +你需要构造一个同时满足下述所有条件的数组 `nums`(下标 从 `0` 开始 计数): * `nums.length == n` * `nums[i]` 是 正整数 ,其中 `0 <= i < n` @@ -56,7 +58,7 @@ Tag : 「二分」、「数学」、「构造」、「贪心」、「模拟」 利用「等差数列求和」公式分别从 `x - 1` 开始构造(注意:这里说的构造仅是计算 $nums$ 总和),若总和不超过 `max` 说明 $nums[idx] = x$ 满足要求,我们令 $l = mid$,否则令 $r = mid - 1$。 -代码: +Java 代码: ```Java class Solution { public int maxValue(int n, int index, int max) { @@ -90,6 +92,104 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int maxValue(int n, int index, int maxSum) { + long l = 1, r = maxSum; + while (l < r) { + long mid = (l + r + 1) >> 1; + if (check(n, mid, index, maxSum)) l = mid; + else r = mid - 1; + } + return (int) r; + } + bool check(int n, long x, int idx, int maxSum) { + long sum = x; + if (idx > x - 1) { + long an = x - 1, a1 = 1, cnt = x - 1; + sum += cnt * (a1 + an) / 2; + sum += idx - cnt; + } else { + long cnt = idx, an = x - 1, a1 = an - cnt + 1; + sum += cnt * (a1 + an) / 2; + } + if (n - idx - 1 > x - 1) { + long an = x - 1, a1 = 1, cnt = x - 1; + sum += cnt * (a1 + an) / 2; + sum += n - idx - 1 - cnt; + } else { + long cnt = n - idx - 1, an = x - 1, a1 = an - cnt + 1; + sum += cnt * (a1 + an) / 2; + } + return sum <= maxSum; + } +}; +``` +Python 代码: +```Python +class Solution: + def maxValue(self, n: int, index: int, maxSum: int) -> int: + l, r = 1, maxSum + while l < r: + mid = (l + r + 1) >> 1 + if self.check(n, mid, index, maxSum): + l = mid + else: + r = mid - 1 + return int(r) + + def check(self, n, x, idx, maxSum): + sumv = x + if idx > x - 1: + an, a1, cnt = x - 1, 1, x - 1 + sumv += cnt * (a1 + an) // 2 + sumv += idx - cnt + else: + cnt, an, a1 = idx, x - 1, x - idx + sumv += cnt * (a1 + an) // 2 + if n - idx - 1 > x - 1: + an, a1, cnt = x - 1, 1, x - 1 + sumv += cnt * (a1 + an) // 2 + sumv += n - idx - 1 - cnt + else: + cnt, an, a1 = n - idx - 1, x - 1, x - n + idx + 1 + sumv += cnt * (a1 + an) // 2 + return sumv <= maxSum +``` +TypeScript 代码: +```TypeScript +function maxValue(n: number, index: number, maxSum: number): number { + const check = function(n: number, x: number, idx: number, maxSum: number): boolean { + let sum = x; + if (idx > x - 1) { + let an = x - 1, a1 = 1, cnt = x - 1; + sum += cnt * (a1 + an) / 2; + sum += idx - cnt; + } else { + let cnt = idx, an = x - 1, a1 = an - cnt + 1; + sum += cnt * (a1 + an) / 2; + } + if (n - idx - 1 > x - 1) { + let an = x - 1, a1 = 1, cnt = x - 1; + sum += cnt * (a1 + an) / 2; + sum += n - idx - 1 - cnt; + } else { + let cnt = n - idx - 1, an = x - 1, a1 = an - cnt + 1; + sum += cnt * (a1 + an) / 2; + } + return sum <= maxSum; + }; + let l = 1, r = maxSum; + while (l < r) { + let mid = (l + r + 1) >> 1; + if (check(n, mid, index, maxSum)) l = mid; + else r = mid - 1; + } + return r; +}; +``` * 时间复杂度:$O(\log{n})$ * 空间复杂度:$O(1)$ diff --git "a/LeetCode/211-220/215. \346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/211-220/215. \346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240\357\274\210\344\270\255\347\255\211\357\274\211.md" index 6dc45bd6..a128f312 100644 --- "a/LeetCode/211-220/215. \346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/211-220/215. \346\225\260\347\273\204\344\270\255\347\232\204\347\254\254K\344\270\252\346\234\200\345\244\247\345\205\203\347\264\240\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -46,10 +46,10 @@ Tag : 「树状数组」、「二分」、「优先队列(堆)」、「快 二分出结果后再减去刚开始添加的偏移量即是答案。 -代码: +Java 代码: ```Java class Solution { - int M = 10010, N = 2 * M; + int M = 100010, N = 2 * M; int[] tr = new int[N]; int lowbit(int x) { return x & -x; @@ -74,6 +74,89 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int N = 200010, M = 100010, tr[200010]; + int lowbit(int x) { + return x & -x; + } + int query(int x) { + int ans = 0; + for (int i = x; i > 0; i -= lowbit(i)) ans += tr[i]; + return ans; + } + void add(int x) { + for (int i = x; i < N; i += lowbit(i)) tr[i]++; + } + int findKthLargest(vector& nums, int k) { + for (int x : nums) add(x + M); + int l = 0, r = N - 1; + while (l < r) { + int mid = l + r + 1 >> 1; + if (query(N - 1) - query(mid - 1) >= k) l = mid; + else r = mid - 1; + } + return r - M; + } +}; +``` +Python 代码: +```Python +class Solution: + def findKthLargest(self, nums: List[int], k: int) -> int: + N, M = 200010, 100010 + tr = [0] * N + def lowbit(x): + return x & -x + def query(x): + ans = 0 + i = x + while i > 0: + ans += tr[i] + i -= lowbit(i) + return ans + def add(x): + i = x + while i < N: + tr[i] += 1 + i += lowbit(i) + for x in nums: + add(x + M) + l, r = 0, N - 1 + while l < r: + mid = l + r + 1 >> 1 + if query(N - 1) - query(mid - 1) >= k: l = mid + else: r = mid - 1 + return r - M +``` +TypeScript 代码: +```TypeScript +function findKthLargest(nums: number[], k: number): number { + const N = 200010, M = 100010; + const tr = new Array(N).fill(0); + const lowbit = function(x: number): number { + return x & -x; + }; + const add = function(x: number): void { + for (let i = x; i < N; i += lowbit(i)) tr[i]++; + }; + const query = function(x: number): number { + let ans = 0; + for (let i = x; i > 0; i -= lowbit(i)) ans += tr[i]; + return ans; + }; + for (const x of nums) add(x + M); + let l = 0, r = N - 1; + while (l < r) { + const mid = l + r + 1 >> 1; + if (query(N - 1) - query(mid - 1) >= k) l = mid; + else r = mid - 1; + } + return r - M; +}; +``` * 时间复杂度:将所有数字放入树状数组复杂度为 $O(n\log{m})$;二分出答案复杂度为 $O(\log^2{m})$,其中 $m = 2 \times 10^4$ 为值域大小。整体复杂度为 $O(n\log{m})$ * 空间复杂度:$O(m)$ @@ -88,7 +171,7 @@ class Solution { * 当优先队列元素不足 $k$ 个,可将当前元素直接放入队列中; * 当优先队列元素达到 $k$ 个,并且当前元素大于栈顶元素(栈顶元素必然不是答案),可将当前元素放入队列中。 -代码: +Java 代码: ```Java class Solution { public int findKthLargest(int[] nums, int k) { @@ -101,6 +184,32 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int findKthLargest(vector& nums, int k) { + priority_queue, greater> q; + for (int x : nums) { + if (q.size() < k || q.top() < x) q.push(x); + if (q.size() > k) q.pop(); + } + return q.top(); + } +}; +``` +Python 代码: +```Python +class Solution: + def findKthLargest(self, nums: List[int], k: int) -> int: + q = [] + for x in nums: + if len(q) < k or q[0] < x: + heapq.heappush(q, x) + if len(q) > k: + heapq.heappop(q) + return q[0] +``` * 时间复杂度:$O(n\log{k})$ * 空间复杂度:$O(k)$ @@ -116,7 +225,7 @@ class Solution { > 快速排序模板为面试向重点内容,需要重要掌握。 -代码: +Java 代码: ```Java class Solution { int[] nums; @@ -143,6 +252,75 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector nums; + int qselect(int l, int r, int k) { + if (l == r) return nums[k]; + int x = nums[l], i = l - 1, j = 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 (k <= j) return qselect(l, j, k); + else return qselect(j + 1, r, k); + } + int findKthLargest(vector& _nums, int k) { + nums = _nums; + int n = nums.size(); + return qselect(0, n - 1, n - k); + } +}; +``` +Python 代码: +```Python +class Solution: + def findKthLargest(self, nums: List[int], k: int) -> int: + def qselect(l, r, k): + if l == r: + return nums[k] + x, i, j = nums[l], l - 1, r + 1 + while i < j: + i += 1 + while nums[i] < x: + i += 1 + j -= 1 + while nums[j] > x: + j -= 1 + if i < j: + nums[i], nums[j] = nums[j], nums[i] + if k <= j: + return qselect(l, j, k) + else: + return qselect(j + 1, r, k) + + n = len(nums) + return qselect(0, n - 1, n - k) +``` +TypeScript 代码: +```TypeScript +function findKthLargest(nums: number[], k: number): number { + const qselect = function(l: number, r: number, k: number): number { + if (l === r) return nums[k]; + const x = nums[l]; + let i = l - 1, j = r + 1; + while (i < j) { + i++; + while (nums[i] < x) i++; + j--; + while (nums[j] > x) j--; + if (i < j) [nums[i], nums[j]] = [nums[j], nums[i]]; + } + if (k <= j) return qselect(l, j, k); + else return qselect(j + 1, r, k); + }; + const n = nums.length; + return qselect(0, n - 1, n - k); +}; +``` * 时间复杂度:期望 $O(n)$ * 空间复杂度:忽略递归带来的额外空间开销,复杂度为 $O(1)$ diff --git "a/LeetCode/231-240/236. \344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/231-240/236. \344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210\357\274\210\344\270\255\347\255\211\357\274\211.md" index 6decf6e1..335a8297 100644 --- "a/LeetCode/231-240/236. \344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/231-240/236. \344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -51,7 +51,7 @@ Tag : 「二叉树」、「DFS」、「递归」 常见的 `LCA` 问题。 -设计 `DFS` 函数 `boolean dfs(TreeNode cur, TreeNode t, List path)`:其中 **`cur` 为当前处理到的节点,`t` 为需要找到的目的节点,`path` 为从根节点到当前节点 `cur` 所经过的路径**。若能够以当前节点 `cur` 为根的子树包含目标节点 `t`,函数返回 `true`,否则返回 `false`。 +设计 `DFS` 函数 `boolean dfs(TreeNode cur, TreeNode t, List path)`:其中 **`cur` 为当前处理到的节点,`t` 为需要找到的目的节点,`path` 为从根节点到当前节点 `cur` 所经过的路径**。若能够以当前节点 `cur` 为根的子树包含目标节点 `t`,函数返回 `true`,否则返回 `false`。z 调用函数分别传入 `p` 和 `q` 作为目标节点,从而得到从根节点到 `p` 和 `q` 的路径列表,遍历路径找到最后一个相同的节点即是答案。 diff --git "a/LeetCode/481-490/481. \347\245\236\345\245\207\345\255\227\347\254\246\344\270\262\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/481-490/481. \347\245\236\345\245\207\345\255\227\347\254\246\344\270\262\357\274\210\344\270\255\347\255\211\357\274\211.md" index e3dc226b..2d420f63 100644 --- "a/LeetCode/481-490/481. \347\245\236\345\245\207\345\255\227\347\254\246\344\270\262\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/481-490/481. \347\245\236\345\245\207\345\255\227\347\254\246\344\270\262\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -10,7 +10,9 @@ Tag : 「模拟」、「构造」、「双指针」、「打表」 * 神奇字符串 `s` 的神奇之处在于,串联字符串中 `'1'` 和 `'2'` 的连续出现次数可以生成该字符串。 -`s` 的前几个元素是 `s = "1221121221221121122……"` 。如果将 `s` 中连续的若干 `1` 和 `2` 进行分组,可以得到 `"1 22 11 2 1 22 1 22 11 2 11 22 ......"` 。每组中 `1` 或者 `2` 的出现次数分别是 `"1 2 2 1 1 2 1 2 2 1 2 2 ......"` 。上面的出现次数正是 s 自身。 +`s` 的前几个元素是 `s = "1221121221221121122……"` 。如果将 `s` 中连续的若干 `1` 和 `2` 进行分组,可以得到 `"1 22 11 2 1 22 1 22 11 2 11 22 ......"` 。 + +每组中 `1` 或者 `2` 的出现次数分别是 `"1 2 2 1 1 2 1 2 2 1 2 2 ......"` 。上面的出现次数正是 `s` 自身。 给你一个整数 `n` ,返回在神奇字符串 `s` 的前 `n` 个数字中 `1` 的数目。 @@ -89,41 +91,42 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function magicalString(n: number): number { - let str = '01' // 首位多加一个 0 作为哨兵 - const f = new Array(n + 10).fill(0) - for (let i = 1, j = 1, cnt = 0; i <= n; j++) { - const last = str[str.length - 1], t = str[j] - if (last == '1') { - if (t == '1') { - // 当原串当前字符是 1,而计数串当前字符为 1 - // 往后构造形成的原串只能是 12,原串指针后移一位 - str += '2' - f[i] = ++cnt; i++ - } else { - // 当原串当前字符是 1,而计数串当前字符为 2 - // 往后构造形成的原串只能是 112,此时同步更新 f[i + 1],原串指针后移两位 - str += '12' - f[i] = ++cnt; f[i + 1] = ++cnt; i += 2 - } - } else { - if (t == '1') { - // 当原串当前字符是 2,而计数串当前字符为 1 - // 往后构造形成的原串只能是 21,原串指针后移一位 - str += '1' - f[i] = cnt; i++ +C++ 代码: +```C++ +class Solution { +public: + static const int N = 100010; + static vector f; + Solution() { + if(!f.empty()) return; + f.resize(N); + string sb = "01"; // 首位多加一个 0 作为哨兵 + for (int i = 1, j = 1, cnt = 0; i < N; j++) { + int last = sb[sb.size() - 1] - '0', t = sb[j] - '0'; + if (last == 1) { + if (t == 1) { + sb += '2'; + f[i++] = ++cnt; + } else { + sb += "12"; + f[i++] = ++cnt; f[i++] = ++cnt; + } } else { - // 当原串当前字符是 2,而计数串当前字符为 2 - // 往后构造形成的原串只能是 221,原串指针后移两位 - str += '21' - f[i] = f[i + 1] = cnt; i += 2 + if (t == 1) { + sb += '1'; + f[i++] = cnt; + } else { + sb += "21"; + f[i++] = f[i++] = cnt; + } } } } - return f[n] -} + int magicalString(int n) { + return f[n]; + } +}; +vector Solution::f = {}; ``` Python 代码: ```Python @@ -159,6 +162,42 @@ class Solution: j += 1 return f[n] ``` +TypeScript 代码: +```TypeScript +function magicalString(n: number): number { + let str = '01' // 首位多加一个 0 作为哨兵 + const f = new Array(n + 10).fill(0) + for (let i = 1, j = 1, cnt = 0; i <= n; j++) { + const last = str[str.length - 1], t = str[j] + if (last == '1') { + if (t == '1') { + // 当原串当前字符是 1,而计数串当前字符为 1 + // 往后构造形成的原串只能是 12,原串指针后移一位 + str += '2' + f[i] = ++cnt; i++ + } else { + // 当原串当前字符是 1,而计数串当前字符为 2 + // 往后构造形成的原串只能是 112,此时同步更新 f[i + 1],原串指针后移两位 + str += '12' + f[i] = ++cnt; f[i + 1] = ++cnt; i += 2 + } + } else { + if (t == '1') { + // 当原串当前字符是 2,而计数串当前字符为 1 + // 往后构造形成的原串只能是 21,原串指针后移一位 + str += '1' + f[i] = cnt; i++ + } else { + // 当原串当前字符是 2,而计数串当前字符为 2 + // 往后构造形成的原串只能是 221,原串指针后移两位 + str += '21' + f[i] = f[i + 1] = cnt; i += 2 + } + } + } + return f[n] +} +``` * 时间复杂度:$O(n)$,若将 `static` 打表逻辑放到本地进行,能够减少构造的计算量,但仍会有创建答案数组的 $O(n)$ 开销,因此为均摊 $O(1)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/541-550/543. \344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204\357\274\210\347\256\200\345\215\225\357\274\211.md" "b/LeetCode/541-550/543. \344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204\357\274\210\347\256\200\345\215\225\357\274\211.md" index e7728b05..f0305673 100644 --- "a/LeetCode/541-550/543. \344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204\357\274\210\347\256\200\345\215\225\357\274\211.md" +++ "b/LeetCode/541-550/543. \344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204\357\274\210\347\256\200\345\215\225\357\274\211.md" @@ -6,13 +6,13 @@ Tag : 「二叉树」、「DFS」 -给你一棵二叉树的根节点,返回该树的 直径 。 +给你一棵二叉树的根节点,返回该树的直径。 -二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。 +二叉树的直径是指树中任意两个节点之间最长路径的长度。 这条路径可能经过也可能不经过根节点 `root`。 -两节点之间路径的 长度 由它们之间边数表示。 +两节点之间路径的长度由它们之间边数表示。 示例 1: ![](https://assets.leetcode.com/uploads/2021/03/06/diamtree.jpg) @@ -46,7 +46,7 @@ Tag : 「二叉树」、「DFS」 同时,`l + r` 则是以当前节点 `u` 为路径最高点时的路径长度,用此更新全局 `ans` 即可。 -代码: +Java 代码: ```Java class Solution { int ans = 0; @@ -62,6 +62,51 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int ans = 0; + int diameterOfBinaryTree(TreeNode* root) { + dfs(root); + return ans; + } + int dfs(TreeNode* u) { + if (u == NULL) return 0; + int l = dfs(u->left), r = dfs(u->right); + ans = max(ans, l + r); + return max(l, r) + 1; + } +}; +``` +Python 代码: +```Python +class Solution: + def diameterOfBinaryTree(self, root: TreeNode) -> int: + ans = 0 + def dfs(u): + nonlocal ans + if not u: return 0 + left, right = dfs(u.left), dfs(u.right) + ans = max(ans, left + right) + return max(left, right) + 1 + dfs(root) + return ans +``` +TypeScript 代码: +```TypeScript +function diameterOfBinaryTree(root: TreeNode | null): number { + let ans = 0; + const dfs = function(u: TreeNode): number { + if (!u) return 0; + const l = dfs(u.left), r = dfs(u.right); + ans = Math.max(ans, l + r); + return Math.max(l, r) + 1; + }; + dfs(root); + return ans; +}; +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/631-640/636. \345\207\275\346\225\260\347\232\204\347\213\254\345\215\240\346\227\266\351\227\264\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/631-640/636. \345\207\275\346\225\260\347\232\204\347\213\254\345\215\240\346\227\266\351\227\264\357\274\210\344\270\255\347\255\211\357\274\211.md" index 3a28d12d..b13b5425 100644 --- "a/LeetCode/631-640/636. \345\207\275\346\225\260\347\232\204\347\213\254\345\215\240\346\227\266\351\227\264\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/631-640/636. \345\207\275\346\225\260\347\232\204\347\213\254\345\215\240\346\227\266\351\227\264\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,13 +6,21 @@ Tag : 「模拟」、「栈」 -有一个单线程 `CPU` 正在运行一个含有 `n` 道函数的程序。每道函数都有一个位于  `0` 和 `n-1` 之间的唯一标识符。 +有一个单线程 `CPU` 正在运行一个含有 `n` 道函数的程序。 -函数调用 存储在一个调用栈上 :当一个函数调用开始时,它的标识符将会推入栈中。而当一个函数调用结束时,它的标识符将会从栈中弹出。标识符位于栈顶的函数是当前正在执行的函数。每当一个函数开始或者结束时,将会记录一条日志,包括函数标识符、是开始还是结束、以及相应的时间戳。 +每道函数都有一个位于  `0` 和 `n-1` 之间的唯一标识符。 -给你一个由日志组成的列表 `logs` ,其中 `logs[i]` 表示第 `i` 条日志消息,该消息是一个按 `"{function_id}:{"start" | "end"}:{timestamp}"` 进行格式化的字符串。例如,`"0:start:3"` 意味着标识符为 `0` 的函数调用在时间戳 `3` 的 起始开始执行 ;而 `"1:end:2"` 意味着标识符为 `1` 的函数调用在时间戳 `2` 的末尾结束执行。注意,函数可以调用多次,可能存在递归调用 。 +函数调用存储在一个调用栈上 :当一个函数调用开始时,它的标识符将会推入栈中。而当一个函数调用结束时,它的标识符将会从栈中弹出。标识符位于栈顶的函数是当前正在执行的函数。每当一个函数开始或者结束时,将会记录一条日志,包括函数标识符、是开始还是结束、以及相应的时间戳。 -函数的「独占时间」定义是在这个函数在程序所有函数调用中执行时间的总和,调用其他函数花费的时间不算该函数的独占时间。例如,如果一个函数被调用两次,一次调用执行 `2` 单位时间,另一次调用执行 `1` 单位时间,那么该函数的独占时间为 `2 + 1 = 3` 。 +给你一个由日志组成的列表 `logs` ,其中 `logs[i]` 表示第 `i` 条日志消息,该消息是一个按 `"{function_id}:{"start" | "end"}:{timestamp}"` 进行格式化的字符串。 + +例如,`"0:start:3"` 意味着标识符为 `0` 的函数调用在时间戳 `3` 的 起始开始执行 ;而 `"1:end:2"` 意味着标识符为 `1` 的函数调用在时间戳 `2` 的末尾结束执行。 + +注意,函数可以调用多次,可能存在递归调用 。 + +函数的「独占时间」定义是在这个函数在程序所有函数调用中执行时间的总和,调用其他函数花费的时间不算该函数的独占时间。 + +例如,如果一个函数被调用两次,一次调用执行 `2` 单位时间,另一次调用执行 `1` 单位时间,那么该函数的独占时间为 `2 + 1 = 3` 。 以数组形式返回每个函数的独占时间,其中第 `i` 个下标对应的值表示标识符 `i` 的函数的独占时间。 @@ -114,6 +122,55 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector exclusiveTime(int n, vector& logs) { + vector ans(n, 0); + stack s; + int cur = -1; + for (auto log : logs) { + istringstream ss(log); + string buf; + vector tokens; + while (getline(ss, buf, ':')) { + tokens.push_back(buf); + } + int idx = stoi(tokens[0]), ts = stoi(tokens[2]); + if (tokens[1] == "start") { + if (!s.empty()) ans[s.top()] += ts - cur; + s.push(idx); + cur = ts; + } else { + ans[s.top()] += ts - cur + 1; + s.pop(); + cur = ts + 1; + } + } + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def exclusiveTime(self, n: int, logs: List[str]) -> List[int]: + ans = [0] * n + s = [] + cur = -1 + for log in logs: + ss = log.split(':') + idx, ts = int(ss[0]), int(ss[2]) + if ss[1] == "start": + if s: ans[s[-1]] += ts - cur + s.append(idx) + cur = ts + else: + ans[s.pop()] += ts - cur + 1 + cur = ts + 1 + return ans +``` TypeScript 代码: ```TypeScript function exclusiveTime(n: number, logs: string[]): number[] { diff --git "a/LeetCode/661-670/662. \344\272\214\345\217\211\346\240\221\346\234\200\345\244\247\345\256\275\345\272\246\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/661-670/662. \344\272\214\345\217\211\346\240\221\346\234\200\345\244\247\345\256\275\345\272\246\357\274\210\344\270\255\347\255\211\357\274\211.md" index 77ca7506..9ec98a97 100644 --- "a/LeetCode/661-670/662. \344\272\214\345\217\211\346\240\221\346\234\200\345\244\247\345\256\275\345\272\246\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/661-670/662. \344\272\214\345\217\211\346\240\221\346\234\200\345\244\247\345\256\275\345\272\246\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,11 +6,13 @@ Tag : 「二叉树」、「DFS」、「哈希表」 -给你一棵二叉树的根节点 `root`,返回树的 最大宽度 。 +给你一棵二叉树的根节点 `root`,返回树的最大宽度。 -树的 最大宽度 是所有层中最大的 宽度 。 +树的「最大宽度」是所有层中最大的宽度 。 -每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 `null` 节点,这些 `null` 节点也计入长度。 +每一层的宽度被定义为该层最左和最右的非空节点(即两个端点)之间的长度。 + +将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 `null` 节点,这些 `null` 节点也计入长度。 题目数据保证答案将会在  `32` 位 带符号整数范围内。 @@ -79,6 +81,45 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + unordered_map map; + int ans = 0; + int widthOfBinaryTree(TreeNode* root) { + dfs(root, 1, 0); + return ans; + } + void dfs(TreeNode* root, int u, int depth) { + if (!root) return; + if (!map.count(depth)) map[depth] = u; + ans = max(ans, u - map[depth] + 1); + u = u - map[depth] + 1; + dfs(root->left, u << 1, depth + 1); + dfs(root->right, u << 1 | 1, depth + 1); + } +}; +``` +Python 代码: +```Python +class Solution: + def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int: + mapping = {} + ans = 0 + def dfs(root, u, depth): + nonlocal ans + if not root: + return + if depth not in mapping: + mapping[depth] = u + ans = max(ans, u - mapping[depth] + 1) + u = u - mapping[depth] + 1 + dfs(root.left, u << 1, depth + 1) + dfs(root.right, u << 1 | 1, depth + 1) + dfs(root, 1, 0) + return ans +``` TypeScript 代码: ```TypeScript let map = new Map() diff --git "a/LeetCode/681-690/687. \346\234\200\351\225\277\345\220\214\345\200\274\350\267\257\345\276\204\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/681-690/687. \346\234\200\351\225\277\345\220\214\345\200\274\350\267\257\345\276\204\357\274\210\344\270\255\347\255\211\357\274\211.md" index 5e4f6cf0..840f8344 100644 --- "a/LeetCode/681-690/687. \346\234\200\351\225\277\345\220\214\345\200\274\350\267\257\345\276\204\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/681-690/687. \346\234\200\351\225\277\345\220\214\345\200\274\350\267\257\345\276\204\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -60,6 +60,51 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int maxv = 0; + int dfs(TreeNode* root) { + if (root == nullptr) return 0; + int ans = 0, cur = 0; + int l = dfs(root->left), r = dfs(root->right); + if (root->left != nullptr && root->left->val == root->val) { + ans = l + 1; cur += l + 1; + } + if (root->right != nullptr && root->right->val == root->val) { + ans = max(ans, r + 1); cur += r + 1; + } + maxv = max(maxv, cur); + return ans; + } + int longestUnivaluePath(TreeNode* root) { + dfs(root); + return maxv; + } +}; +``` +Python 代码: +```Python +class Solution: + def longestUnivaluePath(self, root: Optional[TreeNode]) -> int: + maxv = 0 + def dfs(root): + nonlocal maxv + if not root: return 0 + ans, cur = 0, 0 + l, r = dfs(root.left), dfs(root.right) + if root.left and root.left.val == root.val: + ans = l + 1 + cur += l + 1 + if root.right and root.right.val == root.val: + ans = max(ans, r + 1) + cur += r + 1 + maxv = max(maxv, cur) + return ans + dfs(root) + return maxv +``` TypeScript 代码: ```TypeScript let max = 0; diff --git "a/LeetCode/761-770/764. \346\234\200\345\244\247\345\212\240\345\217\267\346\240\207\345\277\227\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/761-770/764. \346\234\200\345\244\247\345\212\240\345\217\267\346\240\207\345\277\227\357\274\210\344\270\255\347\255\211\357\274\211.md" index 46339816..29ad07a0 100644 --- "a/LeetCode/761-770/764. \346\234\200\345\244\247\345\212\240\345\217\267\346\240\207\345\277\227\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/761-770/764. \346\234\200\345\244\247\345\212\240\345\217\267\346\240\207\345\277\227\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -8,9 +8,13 @@ Tag : 「模拟」、「预处理」 在一个 $n \times n$ 的矩阵 `grid` 中,除了在数组 `mines` 中给出的元素为 `0`,其他每个元素都为 `1`。$mines[i] = [x_i, y_i]$ 表示 $grid[x_i][y_i] = 0$。 -返回  `grid` 中包含 `1` 的最大的 轴对齐 加号标志的阶数 。如果未找到加号标志,则返回 `0` 。 +返回  `grid` 中包含 `1` 的最大的轴对齐加号标志的阶数 。 -一个 `k` 阶由 `1` 组成的 “轴对称”加号标志 具有中心网格 $grid[r][c] = 1$ ,以及 `4` 个从中心向上、向下、向左、向右延伸,长度为 `k-1`,由 `1` 组成的臂。注意,只有加号标志的所有网格要求为 `1` ,别的网格可能为 `0` 也可能为 `1` 。 +如果未找到加号标志,则返回 `0` 。 + +一个 `k` 阶由 `1` 组成的 “轴对称”加号标志 具有中心网格 $grid[r][c] = 1$ ,以及 `4` 个从中心向上、向下、向左、向右延伸,长度为 `k-1`,由 `1` 组成的臂。 + +注意,只有加号标志的所有网格要求为 `1` ,别的网格可能为 `0` 也可能为 `1` 。 示例 1: ![](https://assets.leetcode.com/uploads/2021/06/13/plus1-grid.jpg) @@ -81,6 +85,58 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int orderOfLargestPlusSign(int n, vector>& mines) { + vector> g(n + 10, vector(n + 10, 1)); + for (vector& info : mines) g[info[0] + 1][info[1] + 1] = 0; + vector> a(n + 10, vector(n + 10)), b(n + 10, vector(n + 10)), c(n + 10, vector(n + 10)), d(n + 10, vector(n + 10)); + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + if (g[i][j] == 1) { + a[i][j] = a[i - 1][j] + 1; + b[i][j] = b[i][j - 1] + 1; + } + if (g[n + 1 - i][n + 1 - j] == 1) { + c[n + 1 - i][n + 1 - j] = c[n + 2 - i][n + 1 - j] + 1; + d[n + 1 - i][n + 1 - j] = d[n + 1 - i][n + 2 - j] + 1; + } + } + } + int ans = 0; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + ans = max(ans, min(min(a[i][j], b[i][j]), min(c[i][j], d[i][j]))); + } + } + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def orderOfLargestPlusSign(self, n: int, mines: List[List[int]]) -> int: + g = [[1] * (n + 10) for _ in range(n + 10)] + for x, y in mines: + g[x + 1][y + 1] = 0 + a, b, c, d = [[0] * (n + 10) for _ in range(n + 10)], [[0] * (n + 10) for _ in range(n + 10)], [[0] * (n + 10) for _ in range(n + 10)], [[0] * (n + 10) for _ in range(n + 10)] + for i in range(1, n + 1): + for j in range(1, n + 1): + if g[i][j] == 1: + a[i][j] = a[i - 1][j] + 1 + b[i][j] = b[i][j - 1] + 1 + if g[n + 1 - i][n + 1 - j] == 1: + c[n + 1 - i][n + 1 - j] = c[n + 2 - i][n + 1 - j] + 1 + d[n + 1 - i][n + 1 - j] = d[n + 1 - i][n + 2 - j] + 1 + ans = 0 + for i in range(1, n + 1): + for j in range(1, n + 1): + ans = max(ans, min(min(a[i][j], b[i][j]), min(c[i][j], d[i][j]))) + return ans +``` TypeScript 代码: ```TypeScript function orderOfLargestPlusSign(n: number, mines: number[][]): number { @@ -113,28 +169,6 @@ function orderOfLargestPlusSign(n: number, mines: number[][]): number { return ans } ``` -Python 代码: -```Python -class Solution: - def orderOfLargestPlusSign(self, n: int, mines: List[List[int]]) -> int: - g = [[1] * (n + 10) for _ in range(n + 10)] - for x, y in mines: - g[x + 1][y + 1] = 0 - a, b, c, d = [[0] * (n + 10) for _ in range(n + 10)], [[0] * (n + 10) for _ in range(n + 10)], [[0] * (n + 10) for _ in range(n + 10)], [[0] * (n + 10) for _ in range(n + 10)] - for i in range(1, n + 1): - for j in range(1, n + 1): - if g[i][j] == 1: - a[i][j] = a[i - 1][j] + 1 - b[i][j] = b[i][j - 1] + 1 - if g[n + 1 - i][n + 1 - j] == 1: - c[n + 1 - i][n + 1 - j] = c[n + 2 - i][n + 1 - j] + 1 - d[n + 1 - i][n + 1 - j] = d[n + 1 - i][n + 2 - j] + 1 - ans = 0 - for i in range(1, n + 1): - for j in range(1, n + 1): - ans = max(ans, min(min(a[i][j], b[i][j]), min(c[i][j], d[i][j]))) - return ans -``` * 时间复杂度:$O(n^2)$ * 空间复杂度:$O(n^2)$ diff --git "a/LeetCode/761-770/769. \346\234\200\345\244\232\350\203\275\345\256\214\346\210\220\346\216\222\345\272\217\347\232\204\345\235\227\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/761-770/769. \346\234\200\345\244\232\350\203\275\345\256\214\346\210\220\346\216\222\345\272\217\347\232\204\345\235\227\357\274\210\344\270\255\347\255\211\357\274\211.md" index e153f0dc..252ee4f1 100644 --- "a/LeetCode/761-770/769. \346\234\200\345\244\232\350\203\275\345\256\214\346\210\220\346\216\222\345\272\217\347\232\204\345\235\227\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/761-770/769. \346\234\200\345\244\232\350\203\275\345\256\214\346\210\220\346\216\222\345\272\217\347\232\204\345\235\227\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -8,7 +8,9 @@ Tag : 「模拟」 给定一个长度为 `n` 的整数数组 `arr` ,它表示在 $[0, n - 1]$ 范围内的整数的排列。 -我们将 `arr` 分割成若干 块 (即分区),并对每个块单独排序。将它们连接起来后,使得连接的结果和按升序排序后的原数组相同。 +我们将 `arr` 分割成若干块 (即分区),并对每个块单独排序。 + +将它们连接起来后,使得连接的结果和按升序排序后的原数组相同。 返回数组能分成的最多块数量。 @@ -37,7 +39,7 @@ Tag : 「模拟」 * $n = arr.length$ * $1 <= n <= 10$ * $0 <= arr[i] < n$ -* `arr` 中每个元素都 不同 +* `arr` 中每个元素都不同 --- @@ -65,19 +67,23 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function maxChunksToSorted(arr: number[]): number { - let n = arr.length, ans = 0 - for (let i = 0, j = 0, min = n, max = -1; i < n; i++) { - min = Math.min(min, arr[i]) - max = Math.max(max, arr[i]) - if (j == min && i == max) { - ans++; j = i + 1; min = n; max = -1; +C++ 代码: +```C++ +class Solution { +public: + int maxChunksToSorted(vector& arr) { + int n = arr.size(), ans = 0; + int j = 0, minv = n, maxv = -1; + for (int i = 0; i < n; i++) { + minv = min(minv, arr[i]); + maxv = max(maxv, arr[i]); + if (j == minv && i == maxv) { + ans++; j = i + 1; minv = n; maxv = -1; + } } + return ans; } - return ans -} +}; ``` Python 代码: ```Python @@ -91,6 +97,20 @@ class Solution: ans, j, minv, maxv = ans + 1, i + 1, n, -1 return ans ``` +TypeScript 代码: +```TypeScript +function maxChunksToSorted(arr: number[]): number { + let n = arr.length, ans = 0 + for (let i = 0, j = 0, min = n, max = -1; i < n; i++) { + min = Math.min(min, arr[i]) + max = Math.max(max, arr[i]) + if (j == min && i == max) { + ans++; j = i + 1; min = n; max = -1; + } + } + return ans +} +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(1)$ diff --git "a/LeetCode/771-780/777. \345\234\250LR\345\255\227\347\254\246\344\270\262\344\270\255\344\272\244\346\215\242\347\233\270\351\202\273\345\255\227\347\254\246\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/771-780/777. \345\234\250LR\345\255\227\347\254\246\344\270\262\344\270\255\344\272\244\346\215\242\347\233\270\351\202\273\345\255\227\347\254\246\357\274\210\344\270\255\347\255\211\357\274\211.md" index c383084a..e3b5ae73 100644 --- "a/LeetCode/771-780/777. \345\234\250LR\345\255\227\347\254\246\344\270\262\344\270\255\344\272\244\346\215\242\347\233\270\351\202\273\345\255\227\347\254\246\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/771-780/777. \345\234\250LR\345\255\227\347\254\246\344\270\262\344\270\255\344\272\244\346\215\242\347\233\270\351\202\273\345\255\227\347\254\246\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -1,6 +1,6 @@ ### 题目描述 -这是 LeetCode 上的 **[777. 在LR字符串中交换相邻字符](https://leetcode-cn.com/problems/swim-in-rising-water/solution/gong-shui-san-xie-yi-ti-shuang-jie-krusk-7c6o/)** ,难度为 **中等**。 +这是 LeetCode 上的 **[777. 在LR字符串中交换相邻字符](https://leetcode.cn/problems/swap-adjacent-in-lr-string/solutions/1863778/by-ac_oier-ye71/)** ,难度为 **中等**。 Tag : 「双指针」 @@ -44,7 +44,7 @@ XRLXXRRLX 其中「序号」是指在 `LR` 字符串中出现的相对顺序。 -代码: +Java 代码: ```Java class Solution { public boolean canTransform(String start, String end) { @@ -62,6 +62,58 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + bool canTransform(string start, string end) { + int n = start.size(); + int i = 0, j = 0; + while (i < n || j < n) { + while (i < n && start[i] == 'X') i++; + while (j < n && end[j] == 'X') j++; + if (i == n || j == n) return i == j; + if (start[i] != end[j]) return false; + if (start[i] == 'L' && i < j) return false; + if (start[i] == 'R' && i > j) return false; + i++; j++; + } + return i == j; + } +}; +``` +Python 代码: +```Python +class Solution: + def canTransform(self, start: str, end: str) -> bool: + i, j, n = 0, 0, len(start) + while i < n or j < n: + while i < n and start[i] == 'X': i += 1 + while j < n and end[j] == 'X': j += 1 + if i == n or j == n: return i == j + if start[i] != end[j]: return False + if start[i] == 'L' and i < j: return False + if start[i] == 'R' and i > j: return False + i, j = i + 1, j + 1 + return i == j +``` +TypeScript 代码: +```TypeScript +function canTransform(start: string, end: string): boolean { + let n = start.length; + let i = 0, j = 0; + while (i < n || j < n) { + while (i < n && start.charAt(i) === 'X') i++; + while (j < n && end.charAt(j) === 'X') j++; + if (i === n || j === n) return i === j; + if (start.charAt(i) !== end.charAt(j)) return false; + if (start.charAt(i) === 'L' && i < j) return false; + if (start.charAt(i) === 'R' && i > j) return false; + i++; j++; + } + return i === j; +}; +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(1)$ diff --git "a/LeetCode/781-790/790. \345\244\232\347\261\263\350\257\272\345\222\214\346\211\230\347\261\263\350\257\272\345\271\263\351\223\272\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/781-790/790. \345\244\232\347\261\263\350\257\272\345\222\214\346\211\230\347\261\263\350\257\272\345\271\263\351\223\272\357\274\210\344\270\255\347\255\211\357\274\211.md" index f38c5b80..28380219 100644 --- "a/LeetCode/781-790/790. \345\244\232\347\261\263\350\257\272\345\222\214\346\211\230\347\261\263\350\257\272\345\271\263\351\223\272\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/781-790/790. \345\244\232\347\261\263\350\257\272\345\222\214\346\211\230\347\261\263\350\257\272\345\271\263\351\223\272\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -2,17 +2,19 @@ 这是 LeetCode 上的 **[790. 多米诺和托米诺平铺](https://leetcode.cn/problems/domino-and-tromino-tiling/solution/gong-shui-san-xie-by-ac_oier-kuv4/)** ,难度为 **中等**。 -Tag : 「状态机 DP」 +Tag : 「状态机 DP」、「动态规划」 -有两种形状的瓷砖:一种是 `2 x 1` 的多米诺形,另一种是形如 `"L"` 的托米诺形。两种形状都可以旋转。 +有两种形状的瓷砖:一种是 `2 x 1` 的多米诺形,另一种是形如 `"L"` 的托米诺形,两种形状都可以旋转。 ![](https://assets.leetcode.com/uploads/2021/07/15/lc-domino.jpg) -给定整数 `n` ,返回可以平铺 `2 x n` 的面板的方法的数量。返回对 $10^9 + 7$ 取模 的值。 +给定整数 `n` ,返回可以平铺 `2 x n` 的面板的方法的数量,返回对 $10^9 + 7$ 取模 的值。 -平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。 +平铺指的是每个正方形都必须有瓷砖覆盖。 + +两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。 示例 1: ![](https://assets.leetcode.com/uploads/2021/07/15/lc-domino1.jpg) @@ -41,7 +43,7 @@ Tag : 「状态机 DP」 其中 $j$ 取值范围为 $[0, 4)$ 分别对应了当前列的填充情况: -![image.png](https://pic.leetcode.cn/1668221823-xIysQK-image.png) +![](https://pic.leetcode.cn/1668221823-xIysQK-image.png) 为了方便,我们人为规定列数从 $1$ 开始。 @@ -63,13 +65,13 @@ $$ * $f[i][0]$ : 需要前 $i - 1$ 列铺满,同时第 $i$ 列没有被铺,只能由 $f[i - 1][1]$ 转移而来,即有 $f[i][0] = f[i - 1][1]$ > 这里需要尤其注意:虽然我们能够在上一步留空第 $i - 1$ 列,然后在 $i - 1$ 列竖放一块 $1 \times 2$ 的骨牌(如下图) - ![image.png](https://pic.leetcode.cn/1668224248-NwNCNm-image.png) + ![](https://pic.leetcode.cn/1668224248-NwNCNm-image.png) > 但我们不能从 $f[i - 1][0]$ 转移到 $f[i][0]$,因为此时放置的骨牌,仅对第 $i - 1$ 列产生影响,不会对第 $i$ 列产生影响,该决策所产生的方案数,已在 $f[i - 1][X]$ 时被统计 * $f[i][1]$ : 可由 $f[i - 1][j]$ 转移而来(见下图),其中 $j \in [0, 4)$,即有 $f[i][1] = \sum_{j = 0}^{3} f[i - 1][j]$ - ![image.png](https://pic.leetcode.cn/1668225376-fiLnws-image.png) + ![](https://pic.leetcode.cn/1668225376-fiLnws-image.png) * $f[i][2]$ : 可由 $f[i - 1][0]$ 和 $f[i - 1][3]$ 转移而来 @@ -94,6 +96,39 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { + const int MOD = 1e9 + 7; +public: + int numTilings(int n){ + vector> f(n + 10, vector(4)); + f[1][0] = f[1][1] = 1; + for (int i = 2; i <= n; ++i){ + f[i][0] = f[i - 1][1]; + int cur = 0; + for (int j = 0; j < 4; ++j) cur = (cur + f[i - 1][j]) % MOD; + f[i][1] = cur; + f[i][2] = (f[i - 1][0] + f[i - 1][3]) % MOD; + f[i][3] = (f[i - 1][0] + f[i - 1][2]) % MOD; + } + return f[n][1]; + } +}; +``` +Python3 代码: +```Python +class Solution: + def numTilings(self, n: int) -> int: + f = [[0] * 4 for _ in range(n + 10)] + f[1][0] = f[1][1] = 1 + for i in range(2, n + 1): + f[i][0] = f[i - 1][1] + f[i][1] = sum([f[i - 1][j] for j in range(4)]) + f[i][2] = f[i - 1][0] + f[i - 1][3] + f[i][3] = f[i - 1][0] + f[i - 1][2] + return f[n][1] % 1000000007 +``` TypeScript 代码: ```TypeScript function numTilings(n: number): number { @@ -112,19 +147,6 @@ function numTilings(n: number): number { return f[n][1] } ``` -Python3 代码: -```Python3 -class Solution: - def numTilings(self, n: int) -> int: - f = [[0] * 4 for _ in range(n + 10)] - f[1][0] = f[1][1] = 1 - for i in range(2, n + 1): - f[i][0] = f[i - 1][1] - f[i][1] = sum([f[i - 1][j] for j in range(4)]) - f[i][2] = f[i - 1][0] + f[i - 1][3] - f[i][3] = f[i - 1][0] + f[i - 1][2] - return f[n][1] % 1000000007 -``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(n)$ @@ -154,6 +176,41 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { + const int MOD = 1e9 + 7; +public: + int numTilings(int n){ + vector> f(2, vector(4)); + f[1][0] = f[1][1] = 1; + for (int i = 2; i <= n; ++i){ + int a = i & 1, b = (i - 1) & 1; + f[a][0] = f[b][1]; + int cur = 0; + for (int j = 0; j < 4; ++j) cur = (cur + f[b][j]) % MOD; + f[a][1] = cur; + f[a][2] = (f[b][0] + f[b][3]) % MOD; + f[a][3] = (f[b][0] + f[b][2]) % MOD; + } + return f[n & 1][1]; + } +}; +``` +Python3 代码: +```Python +class Solution: + def numTilings(self, n: int) -> int: + f = [[0] * 4 for _ in range(2)] + f[1][0] = f[1][1] = 1 + for i in range(2, n + 1): + a, b = i & 1, (i - 1) & 1 + f[a][0] = f[b][1] + f[a][1] = sum([f[b][j] for j in range(4)]) + f[a][2] = f[b][0] + f[b][3] + f[a][3] = f[b][0] + f[b][2] + return f[n & 1][1] % 1000000007 +``` TypeScript 代码: ```TypeScript function numTilings(n: number): number { @@ -173,20 +230,6 @@ function numTilings(n: number): number { return f[n & 1][1] } ``` -Python3 代码: -```Python3 -class Solution: - def numTilings(self, n: int) -> int: - f = [[0] * 4 for _ in range(2)] - f[1][0] = f[1][1] = 1 - for i in range(2, n + 1): - a, b = i & 1, (i - 1) & 1 - f[a][0] = f[b][1] - f[a][1] = sum([f[b][j] for j in range(4)]) - f[a][2] = f[b][0] + f[b][3] - f[a][3] = f[b][0] + f[b][2] - return f[n & 1][1] % 1000000007 -``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(1)$ diff --git "a/LeetCode/791-800/791. \350\207\252\345\256\232\344\271\211\345\255\227\347\254\246\344\270\262\346\216\222\345\272\217\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/791-800/791. \350\207\252\345\256\232\344\271\211\345\255\227\347\254\246\344\270\262\346\216\222\345\272\217\357\274\210\344\270\255\347\255\211\357\274\211.md" index 529379ef..c24771c7 100644 --- "a/LeetCode/791-800/791. \350\207\252\345\256\232\344\271\211\345\255\227\347\254\246\344\270\262\346\216\222\345\272\217\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/791-800/791. \350\207\252\345\256\232\344\271\211\345\255\227\347\254\246\344\270\262\346\216\222\345\272\217\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,11 +6,15 @@ Tag : 「构造」、「模拟」 -给定两个字符串 `order` 和 `s` 。`order` 的所有单词都是 唯一 的,并且以前按照一些自定义的顺序排序。 +给定两个字符串 `order` 和 `s` 。 -对 `s` 的字符进行置换,使其与排序的 `order` 相匹配。更具体地说,如果在 `order` 中的字符 `x` 出现字符 `y` 之前,那么在排列后的字符串中, `x` 也应该出现在 `y` 之前。 +`order` 的所有单词都是唯一的,并且以前按照一些自定义的顺序排序。 -返回 满足这个性质的 `s` 的任意排列 。 +对 `s` 的字符进行置换,使其与排序的 `order` 相匹配。 + +更具体地说,如果在 `order` 中的字符 `x` 出现字符 `y` 之前,那么在排列后的字符串中, `x` 也应该出现在 `y` 之前。 + +返回满足这个性质的 `s` 的任意排列 。 示例 1: ``` @@ -60,20 +64,23 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function customSortString(order: string, s: string): string { - const cnts = new Array(26).fill(0) - for (const c of s) cnts[c.charCodeAt(0) - 'a'.charCodeAt(0)]++ - let ans = '' - for (const c of order) { - while (cnts[c.charCodeAt(0) - 'a'.charCodeAt(0)]-- > 0) ans += c - } - for (let i = 0; i < 26; i++) { - while (cnts[i]-- > 0) ans += String.fromCharCode(i + 'a'.charCodeAt(0)); +C++ 代码: +```C++ +class Solution { +public: + string customSortString(string order, string s) { + vector cnts(26, 0); + for (char c : s) cnts[c - 'a']++; + string result = ""; + for (char c : order) { + while (cnts[c - 'a']-- > 0) result += c; + } + for (int i = 0; i < 26; i++) { + while (cnts[i]-- > 0) result += (char)(i + 'a'); + } + return result; } - return ans -} +}; ``` Python 代码: ```Python @@ -93,6 +100,21 @@ class Solution: ans += chr(i + ord('a')) * cnts[i] return ans ``` +TypeScript 代码: +```TypeScript +function customSortString(order: string, s: string): string { + const cnts = new Array(26).fill(0) + for (const c of s) cnts[c.charCodeAt(0) - 'a'.charCodeAt(0)]++ + let ans = '' + for (const c of order) { + while (cnts[c.charCodeAt(0) - 'a'.charCodeAt(0)]-- > 0) ans += c + } + for (let i = 0; i < 26; i++) { + while (cnts[i]-- > 0) ans += String.fromCharCode(i + 'a'.charCodeAt(0)); + } + return ans +} +``` * 时间复杂度:$O(n + m)$ * 空间复杂度:$O(C)$,其中 $C = 26$ 为字符集大小 diff --git "a/LeetCode/801-810/805. \346\225\260\347\273\204\347\232\204\345\235\207\345\200\274\345\210\206\345\211\262\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/801-810/805. \346\225\260\347\273\204\347\232\204\345\235\207\345\200\274\345\210\206\345\211\262\357\274\210\345\233\260\351\232\276\357\274\211.md" index aad6bdcb..00fa3c4a 100644 --- "a/LeetCode/801-810/805. \346\225\260\347\273\204\347\232\204\345\235\207\345\200\274\345\210\206\345\211\262\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/801-810/805. \346\225\260\347\273\204\347\232\204\345\235\207\345\200\274\345\210\206\345\211\262\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -6,7 +6,7 @@ Tag : 「折半搜索」、「二进制枚举」、「哈希表」 -给定你一个整数数组 `nums` +给定你一个整数数组 `nums`。 我们要将 `nums` 数组中的每个元素移动到 `A` 数组 或者 `B` 数组中,使得 `A` 数组和 `B` 数组不为空,并且 `average(A) == average(B)` 。 @@ -65,7 +65,7 @@ Tag : 「折半搜索」、「二进制枚举」、「哈希表」 因此我们可以直接枚举系数 $k$ 来进行判定,其中 $k$ 的取值范围为 $[\max(1, cnt'), n - 1]$,结合上式算得 $t = k \times \frac{sum}{n}$,若在缓存结果中存在 $(t - tot', k - cnt')$,说明存在合法方案。 -代码: +Java 代码: ```Java class Solution { public boolean splitArraySameAverage(int[] nums) { @@ -102,6 +102,107 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + bool splitArraySameAverage(vector& nums) { + int n = nums.size(), m = n / 2, sum = 0; + for (int x : nums) sum += x; + map> hashMap; + for (int s = 0; s < (1 << m); s++) { + int tot = 0, cnt = 0; + for (int i = 0; i < m; i++) { + if ((s >> i) & 1) { + tot += nums[i]; cnt++; + } + } + hashMap[tot].insert(cnt); + } + for (int s = 0; s < (1 << (n - m)); s++) { + int tot = 0, cnt = 0; + for (int i = 0; i < (n - m); i++) { + if ((s >> i) & 1) { + tot += nums[i + m]; cnt++; + } + } + for (int k = max(1, cnt); k < n; k++) { + if (k * sum % n != 0) continue; + int t = k * sum / n; + if (hashMap.count(t - tot) == 0) continue; + if (!hashMap[t - tot].count(k - cnt)) continue; + return true; + } + } + return false; + } +}; +``` +Python 代码: +```Python +from collections import defaultdict + +class Solution: + def splitArraySameAverage(self, nums: List[int]) -> bool: + n, m = len(nums), len(nums) // 2 + sum_nums = sum(nums) + hash_map = defaultdict(set) + for s in range(1 << m): + tot = cnt = 0 + for i in range(m): + if ((s >> i) & 1): + tot += nums[i] + cnt += 1 + hash_map[tot].add(cnt) + for s in range(1 << (n - m)): + tot = cnt = 0 + for i in range(n - m): + if ((s >> i) & 1): + tot += nums[i + m] + cnt += 1 + for k in range(max(1, cnt), n): + if (k * sum_nums) % n != 0: continue + t = (k * sum_nums) // n + if (t - tot) not in hash_map: continue + if (k - cnt) not in hash_map[t - tot]: continue + return True + return False +``` +TypeScript 代码: +```TypeScript +function splitArraySameAverage(nums: number[]): boolean { + let n = nums.length, m = Math.floor(n / 2), sum = 0; + for (let x of nums) sum += x; + let map = new Map(); + for (let s = 0; s < (1 << m); s++) { + let tot = 0, cnt = 0; + for (let i = 0; i < m; i++) { + if (((s >> i) & 1) == 1) { + tot += nums[i]; cnt++; + } + } + let set = map.get(tot) || new Set(); + set.add(cnt); + map.set(tot, set); + } + for (let s = 0; s < (1 << (n - m)); s++) { + let tot = 0, cnt = 0; + for (let i = 0; i < (n - m); i++) { + if (((s >> i) & 1) == 1) { + tot += nums[i + m]; cnt++; + } + } + for (let k = Math.max(1, cnt); k < n; k++) { + if (k * sum % n != 0) continue; + let t = Math.floor(k * sum / n); + if (!map.has(t - tot)) continue; + if (!map.get(t - tot).has(k - cnt)) continue; + return true; + } + } + return false; +}; +``` * 时间复杂度:对原数组前半部分搜索复杂度为 $O(2^{\frac{n}{2}})$;对原数组后半部分搜索复杂度为 $O(2^{\frac{n}{2}})$,搜索同时检索前半部分的结果需要枚举系数 `k`,复杂度为 $O(n)$。整体复杂度为 $O(n \times 2^{\frac{n}{2}})$ * 空间复杂度:$O(2^{\frac{n}{2}})$ diff --git "a/LeetCode/801-810/808. \345\210\206\346\261\244\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/801-810/808. \345\210\206\346\261\244\357\274\210\344\270\255\347\255\211\357\274\211.md" index f880590a..6f8a6740 100644 --- "a/LeetCode/801-810/808. \345\210\206\346\261\244\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/801-810/808. \345\210\206\346\261\244\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,18 +6,28 @@ Tag : 「数学」、「动态规划」、「线性 DP」 -有 `A` 和 `B` 两种类型 的汤。一开始每种类型的汤有 `n` 毫升。有四种分配操作: +有 `A` 和 `B` 两种类型 的汤,一开始每种类型的汤有 `n` 毫升。 + +有四种分配操作: 1. 提供 `100ml` 的 汤A 和 `0ml` 的 汤B 。 2. 提供 `75ml` 的 汤A 和 `25ml` 的 汤B 。 3. 提供 `50ml` 的 汤A 和 `50ml` 的 汤B 。 4. 提供 `25ml` 的 汤A 和 `75ml` 的 汤B 。 -当我们把汤分配给某人之后,汤就没有了。每个回合,我们将从四种概率同为 `0.25` 的操作中进行分配选择。如果汤的剩余量不足以完成某次操作,我们将尽可能分配。当两种类型的汤都分配完时,停止操作。 +当我们把汤分配给某人之后,汤就没有了。 + +每个回合,我们将从四种概率同为 `0.25` 的操作中进行分配选择。 + +如果汤的剩余量不足以完成某次操作,我们将尽可能分配。 + +当两种类型的汤都分配完时,停止操作。 注意 不存在先分配 `100 ml` 汤B 的操作。 -需要返回的值: 汤A 先分配完的概率 +  汤A和汤B 同时分配完的概率 / 2。返回值在正确答案 $10^{-5}$ 的范围内将被认为是正确的。 +需要返回的值:汤A 先分配完的概率 +  汤A和汤B 同时分配完的概率 / 2。 + +返回值在正确答案 $10^{-5}$ 的范围内将被认为是正确的。 示例 1: ``` @@ -92,6 +102,26 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + double soupServings(int n) { + n = min(200, (int)ceil(n / 25.0)); + vector> f(n + 10, vector(n + 10, 0)); + f[0][0] = 0.5; + for (int j = 1; j <= n; ++j) f[0][j] = 1; + for (int i = 1; i <= n; ++i) { + for (int j = 1; j <= n; ++j) { + double a = f[max(i - 4, 0)][j], b = f[max(i - 3, 0)][max(j - 1, 0)]; + double c = f[max(i - 2, 0)][max(j - 2, 0)], d = f[max(i - 1, 0)][max(j - 3, 0)]; + f[i][j] = 0.25 * (a + b + c + d); + } + } + return f[n][n]; + } +}; +``` Python 代码: ```Python class Solution: @@ -108,6 +138,23 @@ class Solution: f[i][j] = 0.25 * (a + b + c + d) return f[n][n] ``` +TypeScript 代码: +```TypeScript +function soupServings(n: number): number { + n = Math.min(200, Math.ceil(n / 25.0)); + const f: number[][] = Array(n + 10).fill(0).map(() => Array(n + 10).fill(0)); + f[0][0] = 0.5; + for (let j = 1; j <= n; j++) f[0][j] = 1; + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= n; j++) { + let a = f[Math.max(i - 4, 0)][j], b = f[Math.max(i - 3, 0)][Math.max(j - 1, 0)]; + let c = f[Math.max(i - 2, 0)][Math.max(j - 2, 0)], d = f[Math.max(i - 1, 0)][Math.max(j - 3, 0)]; + f[i][j] = 0.25 * (a + b + c + d); + } + } + return f[n][n]; +}; +``` * 时间复杂度:$O(m^2)$,其中 $m = 200$ 为验算值 * 空间复杂度:$O(m^2)$ diff --git "a/LeetCode/861-870/864. \350\216\267\345\217\226\346\211\200\346\234\211\351\222\245\345\214\231\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/861-870/864. \350\216\267\345\217\226\346\211\200\346\234\211\351\222\245\345\214\231\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" index 38a085c1..adf2c8f8 100644 --- "a/LeetCode/861-870/864. \350\216\267\345\217\226\346\211\200\346\234\211\351\222\245\345\214\231\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/861-870/864. \350\216\267\345\217\226\346\211\200\346\234\211\351\222\245\345\214\231\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -6,7 +6,7 @@ Tag : 「BFS」、「状态压缩」 -给定一个二维网格 grid ,其中: +给定一个二维网格 `g`,其中: * `'.'` 代表一个空房间 * `'#'` 代表一堵墙 @@ -14,16 +14,24 @@ Tag : 「BFS」、「状态压缩」 * 小写字母代表钥匙 * 大写字母代表锁 -我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。 +我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。 -假设 `k` 为 钥匙/锁 的个数,且满足 $1 <= k <= 6$,字母表中的前 `k` 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。 +我们不能在网格外面行走,也无法穿过一堵墙。 -返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 `-1` 。 +如果途经一个钥匙,我们就把它捡起来,除非我们手里有对应的钥匙,否则无法通过锁。 + +假设 `k` 为 钥匙/锁 的个数,且满足 $1 <= k <= 6$,字母表中的前 `k` 个字母在网格中都有自己对应的一个小写和一个大写字母。 + +换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。 + +返回获取所有钥匙所需要的移动的最少次数。 + +如果无法获取所有钥匙,返回 `-1` 。 示例 1: ![](https://assets.leetcode.com/uploads/2021/07/23/lc-keys2.jpg) ``` -输入:grid = ["@.a.#","###.#","b.A.B"] +输入:g = ["@.a.#","###.#","b.A.B"] 输出:8 @@ -32,25 +40,25 @@ Tag : 「BFS」、「状态压缩」 示例 2: ![](https://assets.leetcode.com/uploads/2021/07/23/lc-key2.jpg) ``` -输入:grid = ["@..aA","..B#.","....b"] +输入:g = ["@..aA","..B#.","....b"] 输出:6 ``` 示例 3: ![](https://assets.leetcode.com/uploads/2021/07/23/lc-keys3.jpg) ``` -输入: grid = ["@Aa"] +输入: g = ["@Aa"] 输出: -1 ``` 提示: -* $m == grid.length$ -* $n == grid[i].length$ +* $m = g.length$ +* $n = g[i].length$ * $1 <= m, n <= 30$ -* `grid[i][j]` 只含有 `'.'`,`'#'`, `'@'`, `'a'-'f'` 以及 `'A'-'F'` +* `g[i][j]` 只含有 `'.'`,`'#'`, `'@'`, `'a'-'f'` 以及 `'A'-'F'` * 钥匙的数目范围是 $[1, 6]$ -* 每个钥匙都对应一个 不同 的字母 +* 每个钥匙都对应一个不同的字母 * 每个钥匙正好打开一个对应的锁 --- @@ -120,45 +128,47 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function shortestPathAllKeys(g: string[]): number { - const dirs = [[1,0],[-1,0],[0,1],[0,-1]] - let n = g.length, m = g[0].length, cnt = 0 - const dist = new Array>>() - for (let i = 0; i < n; i++) { - dist[i] = new Array>(m) - for (let j = 0; j < m; j++) { - dist[i][j] = new Array(1 << 10).fill(0x3f3f3f3f) - } - } - const d = [] - for (let i = 0; i < n; i++) { - for (let j = 0; j < m; j++) { - if (g[i][j] == '@') { - d.push([i, j, 0]); dist[i][j][0] = 0 - } else if (g[i][j] >= 'a' && g[i][j] <= 'z') cnt++ +C++ 代码: +```C++ +class Solution { + int N = 35, K = 10, INF = 0x3f3f3f3f; + vector>> dist = vector>>(N, vector>(N, vector(1<> dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}}; +public: + int shortestPathAllKeys(vector& g) { + int n = g.size(), m = g[0].size(), cnt = 0; + queue> d; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + fill(dist[i][j].begin(), dist[i][j].end(), INF); + char c = g[i][j]; + if (c == '@') { + d.push({i, j, 0}); + dist[i][j][0] = 0; + } else if (c >= 'a' && c <= 'z') cnt++; + } } - } - while (d.length > 0) { - const info = d.shift() - const x = info[0], y = info[1], cur = info[2], step = dist[x][y][cur] - for (const di of dirs) { - const nx = x + di[0], ny = y + di[1] - if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue - const c = g[nx][ny] - if (c == '#') continue - if ('A' <= c && c <= 'Z' && ((cur >> (c.charCodeAt(0) - 'A'.charCodeAt(0)) & 1) == 0)) continue - let ncur = cur - if ('a' <= c && c <= 'z') ncur |= 1 << (c.charCodeAt(0) - 'a'.charCodeAt(0)) - if (ncur == (1 << cnt) - 1) return step + 1 - if (step + 1 >= dist[nx][ny][ncur]) continue - d.push([nx, ny, ncur]) - dist[nx][ny][ncur] = step + 1 + while (!d.empty()) { + vector info = d.front(); + d.pop(); + int x = info[0], y = info[1], cur = info[2], step = dist[x][y][cur]; + for (vector di : dirs) { + int nx = x + di[0], ny = y + di[1]; + if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue; + char c = g[nx][ny]; + if (c == '#') continue; + if ((c >= 'A' && c <= 'Z') && (cur >> (c - 'A') & 1) == 0) continue; + int ncur = cur; + if (c >= 'a' && c <= 'z') ncur |= 1 << (c - 'a'); + if (ncur == (1 << cnt) - 1) return step + 1; + if (step + 1 >= dist[nx][ny][ncur]) continue; + dist[nx][ny][ncur] = step + 1; + d.push({nx, ny, ncur}); + } } + return -1; } - return -1 -} +}; ``` Python3 代码: ```Python @@ -198,6 +208,46 @@ class Solution: d.append((nx, ny, ncur)) return -1 ``` +TypeScript 代码: +```TypeScript +function shortestPathAllKeys(g: string[]): number { + const dirs = [[1,0],[-1,0],[0,1],[0,-1]] + let n = g.length, m = g[0].length, cnt = 0 + const dist = new Array>>() + for (let i = 0; i < n; i++) { + dist[i] = new Array>(m) + for (let j = 0; j < m; j++) { + dist[i][j] = new Array(1 << 10).fill(0x3f3f3f3f) + } + } + const d = [] + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if (g[i][j] == '@') { + d.push([i, j, 0]); dist[i][j][0] = 0 + } else if (g[i][j] >= 'a' && g[i][j] <= 'z') cnt++ + } + } + while (d.length > 0) { + const info = d.shift() + const x = info[0], y = info[1], cur = info[2], step = dist[x][y][cur] + for (const di of dirs) { + const nx = x + di[0], ny = y + di[1] + if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue + const c = g[nx][ny] + if (c == '#') continue + if ('A' <= c && c <= 'Z' && ((cur >> (c.charCodeAt(0) - 'A'.charCodeAt(0)) & 1) == 0)) continue + let ncur = cur + if ('a' <= c && c <= 'z') ncur |= 1 << (c.charCodeAt(0) - 'a'.charCodeAt(0)) + if (ncur == (1 << cnt) - 1) return step + 1 + if (step + 1 >= dist[nx][ny][ncur]) continue + d.push([nx, ny, ncur]) + dist[nx][ny][ncur] = step + 1 + } + } + return -1 +} +``` * 时间复杂度:$O(n \times m \times 2^k)$ * 空间复杂度:$O(n \times m \times 2^k)$ diff --git "a/LeetCode/891-900/895. \346\234\200\345\244\247\351\242\221\347\216\207\346\240\210\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/891-900/895. \346\234\200\345\244\247\351\242\221\347\216\207\346\240\210\357\274\210\345\233\260\351\232\276\357\274\211.md" index 13dab4ea..2f746e68 100644 --- "a/LeetCode/891-900/895. \346\234\200\345\244\247\351\242\221\347\216\207\346\240\210\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/891-900/895. \346\234\200\345\244\247\351\242\221\347\216\207\346\240\210\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -56,7 +56,7 @@ freqStack.pop ();//返回 4 ,因为 4, 5 和 7 出现频率最高,但 4 是 将题目给的样例作为 🌰 ,大家可以看看 `cnts`、`map` 和 `max` 三者如何变化,以及 `pop` 的更新逻辑: -![image.png](https://pic.leetcode.cn/1669771856-XhpLSw-image.png) +![](https://pic.leetcode.cn/1669771856-XhpLSw-image.png) Java 代码: ```Java @@ -81,27 +81,26 @@ class FreqStack { } } ``` -TypeScript 代码: -```TypeScript +C++ 代码: +```C++ class FreqStack { - map: Map> = new Map>() - cnst: Map = new Map() - max: number = 0 - push(val: number): void { - if (!this.cnst.has(val)) this.cnst.set(val, 0) - this.cnst.set(val, this.cnst.get(val) + 1) - const c = this.cnst.get(val) - if (!this.map.has(c)) this.map.set(c, new Array()) - this.map.get(c).push(val) - this.max = Math.max(this.max, c) +public: + unordered_map freq; + unordered_map> m; + int maxv = 0; + + void push(int val) { + maxv = max(maxv, ++freq[val]); + m[freq[val]].push_back(val); } - pop(): number { - const ans = this.map.get(this.max).pop() - if (this.map.get(this.max).length == 0) this.max-- - this.cnst.set(ans, this.cnst.get(ans) - 1) - return ans + + int pop() { + int x = m[maxv].back(); + m[maxv].pop_back(); + if (m[freq[x]--].empty()) maxv--; + return x; } -} +}; ``` Python 代码: ```Python @@ -123,6 +122,28 @@ class FreqStack: self.mv -= 0 if self.map[self.mv] else 1 return ans ``` +TypeScript 代码: +```TypeScript +class FreqStack { + map: Map> = new Map>() + cnst: Map = new Map() + max: number = 0 + push(val: number): void { + if (!this.cnst.has(val)) this.cnst.set(val, 0) + this.cnst.set(val, this.cnst.get(val) + 1) + const c = this.cnst.get(val) + if (!this.map.has(c)) this.map.set(c, new Array()) + this.map.get(c).push(val) + this.max = Math.max(this.max, c) + } + pop(): number { + const ans = this.map.get(this.max).pop() + if (this.map.get(this.max).length == 0) this.max-- + this.cnst.set(ans, this.cnst.get(ans) - 1) + return ans + } +} +``` * 时间复杂度:所有操作均为 $O(1)$ * 空间复杂度:所有入栈的节点最多会被存储两次,一次在计数哈希表中,一次在分桶哈希表中,复杂度为 $O(n)$ diff --git a/README.md b/README.md index aaa30876..eeabacce 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ * 年度会员:**有效期加赠两个月!!**; 季度会员:**有效期加赠两周!!** * 年度会员:**获 66.66 微信现金红包!!**; 季度会员:**获 22.22 微信现金红包!!** -* 年度会员:**参与当月丰厚专属实物抽奖(中奖率 $\geq$ 30%)** -* 年度+季度会员:**月度刷题体验券** +* 年度会员:**参与当月丰厚专属实物抽奖(中奖率 $\geq$ 30%)!!** +* 年度+季度会员:**月度刷题体验券!!** 更多福利详情点击 [这里](https://mp.weixin.qq.com/s/aEjHPyT_uaQvwmgyRY7myA) 查阅 🤩