From eec6c20cec04e23ed1ebda7be48e01e2c5166595 Mon Sep 17 00:00:00 2001 From: AC_Oier Date: Sat, 27 Apr 2024 10:05:49 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=201106=E3=80=811210?= =?UTF-8?q?=E3=80=811222=E3=80=811245=E3=80=8111465=E3=80=811766=E3=80=811?= =?UTF-8?q?781=E3=80=81235=E3=80=812335=E3=80=812336=E3=80=81583=E3=80=816?= =?UTF-8?q?21=E3=80=81649=E3=80=81792=E3=80=81809=E3=80=81816=E3=80=81915?= =?UTF-8?q?=E3=80=81934?= 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" | 79 +++++--- ...10\345\233\260\351\232\276\357\274\211.md" | 86 ++++++++- ...10\344\270\255\347\255\211\357\274\211.md" | 177 +++++++++++++++++- ...10\345\233\260\351\232\276\357\274\211.md" | 69 ++++--- ...10\344\270\255\347\255\211\357\274\211.md" | 59 +++--- ...10\345\233\260\351\232\276\357\274\211.md" | 41 ++-- ...10\344\270\255\347\255\211\357\274\211.md" | 69 ++++--- ...10\344\270\255\347\255\211\357\274\211.md" | 2 +- ...10\347\256\200\345\215\225\357\274\211.md" | 71 ++++++- ...10\344\270\255\347\255\211\357\274\211.md" | 27 +++ ...10\344\270\255\347\255\211\357\274\211.md" | 109 ++++++++++- ...10\344\270\255\347\255\211\357\274\211.md" | 47 +++-- ...10\344\270\255\347\255\211\357\274\211.md" | 92 +++++++-- ...10\344\270\255\347\255\211\357\274\211.md" | 4 +- ...10\344\270\255\347\255\211\357\274\211.md" | 67 +++++-- ...10\344\270\255\347\255\211\357\274\211.md" | 80 +++++--- ...10\344\270\255\347\255\211\357\274\211.md" | 48 ++++- ...10\344\270\255\347\255\211\357\274\211.md" | 42 +++-- ...10\344\270\255\347\255\211\357\274\211.md" | 164 ++++++++-------- 19 files changed, 1027 insertions(+), 306 deletions(-) diff --git "a/LeetCode/1101-1110/1106. \350\247\243\346\236\220\345\270\203\345\260\224\350\241\250\350\276\276\345\274\217\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1101-1110/1106. \350\247\243\346\236\220\345\270\203\345\260\224\350\241\250\350\276\276\345\274\217\357\274\210\345\233\260\351\232\276\357\274\211.md" index 8ad5644c..2ad22721 100644 --- "a/LeetCode/1101-1110/1106. \350\247\243\346\236\220\345\270\203\345\260\224\350\241\250\350\276\276\345\274\217\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1101-1110/1106. \350\247\243\346\236\220\345\270\203\345\260\224\350\241\250\350\276\276\345\274\217\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -98,33 +98,36 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function parseBoolExpr(s: string): boolean { - function calc(a: string, b: string, op: string): string { - const x = a == 't', y = b == 't' - const ans = op == '|' ? x || y : x && y - return ans ? 't' : 'f' - } - const nums = new Array(s.length).fill(''), ops = new Array(s.length).fill('') - let idx1 = 0, idx2 = 0 - for (const c of s) { - if (c == ',') continue - if (c == 't' || c == 'f') nums[idx1++] = c - if (c == '|' || c == '&' || c == '!') ops[idx2++] = c - if (c == '(') nums[idx1++] = '-' - if (c == ')') { - let op = ops[--idx2], cur = ' ' - while (idx1 > 0 && nums[idx1 - 1] != '-') { - const top = nums[--idx1] - cur = cur == ' ' ? top : calc(top, cur, op) +C++ 代码: +```C++ +class Solution { +public: + bool parseBoolExpr(string s) { + deque nums, ops; + for (char c : s) { + if (c == ',') continue; + if (c == 't' || c == 'f') nums.push_back(c); + if (c == '|' || c == '&' || c == '!') ops.push_back(c); + if (c == '(') nums.push_back('-'); + if (c == ')') { + char op = ops.back(); ops.pop_back(); + char cur = ' '; + while (!nums.empty() && nums.back() != '-') { + char top = nums.back(); nums.pop_back(); + cur = cur == ' ' ? top : calc(top, cur, op); + } + if (op == '!') cur = cur == 't' ? 'f' : 't'; + nums.pop_back(); nums.push_back(cur); } - if (op == '!') cur = cur == 't' ? 'f' : 't' - idx1--; nums[idx1++] = cur } + return nums.back() == 't'; } - return nums[idx1 - 1] == 't' -} + char calc(char a, char b, char op) { + bool x = a == 't', y = b == 't'; + bool ans = op == '|' ? x | y : x & y; + return ans ? 't' : 'f'; + } +}; ``` Python 代码: ```Python @@ -155,6 +158,34 @@ class Solution: nums.append(cur) return nums[-1] == 't' ``` +TypeScript 代码: +```TypeScript +function parseBoolExpr(s: string): boolean { + function calc(a: string, b: string, op: string): string { + const x = a == 't', y = b == 't' + const ans = op == '|' ? x || y : x && y + return ans ? 't' : 'f' + } + const nums = new Array(s.length).fill(''), ops = new Array(s.length).fill('') + let idx1 = 0, idx2 = 0 + for (const c of s) { + if (c == ',') continue + if (c == 't' || c == 'f') nums[idx1++] = c + if (c == '|' || c == '&' || c == '!') ops[idx2++] = c + if (c == '(') nums[idx1++] = '-' + if (c == ')') { + let op = ops[--idx2], cur = ' ' + while (idx1 > 0 && nums[idx1 - 1] != '-') { + const top = nums[--idx1] + cur = cur == ' ' ? top : calc(top, cur, op) + } + if (op == '!') cur = cur == 't' ? 'f' : 't' + idx1--; nums[idx1++] = cur + } + } + return nums[idx1 - 1] == 't' +} +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/1201-1210/1210. \347\251\277\350\277\207\350\277\267\345\256\253\347\232\204\346\234\200\345\260\221\347\247\273\345\212\250\346\254\241\346\225\260\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1201-1210/1210. \347\251\277\350\277\207\350\277\267\345\256\253\347\232\204\346\234\200\345\260\221\347\247\273\345\212\250\346\254\241\346\225\260\357\274\210\345\233\260\351\232\276\357\274\211.md" index 1fb0a915..3d0f3420 100644 --- "a/LeetCode/1201-1210/1210. \347\251\277\350\277\207\350\277\267\345\256\253\347\232\204\346\234\200\345\260\221\347\247\273\345\212\250\346\254\241\346\225\260\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1201-1210/1210. \347\251\277\350\277\207\350\277\267\345\256\253\347\232\204\346\234\200\345\260\221\347\247\273\345\212\250\346\254\241\346\225\260\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -8,7 +8,9 @@ Tag : 「BFS」 你还记得那条风靡全球的贪吃蛇吗? -我们在一个 `n*n` 的网格上构建了新的迷宫地图,蛇的长度为 `2`,也就是说它会占去两个单元格。蛇会从左上角(`(0, 0)` 和 `(0, 1)`)开始移动。我们用 `0` 表示空单元格,用 `1` 表示障碍物。蛇需要移动到迷宫的右下角(`(n-1, n-2)` 和 `(n-1, n-1)`)。 +我们在一个 `n*n` 的网格上构建了新的迷宫地图,蛇的长度为 `2`,也就是说它会占去两个单元格。蛇会从左上角(`(0, 0)` 和 `(0, 1)`)开始移动。我们用 `0` 表示空单元格,用 `1` 表示障碍物。 + +蛇需要移动到迷宫的右下角(`(n-1, n-2)` 和 `(n-1, n-1)`)。 每次移动,蛇可以这样走: @@ -75,8 +77,7 @@ Tag : 「BFS」 在得到新蛇尾位置 $(nx, ny)$ 之后,计算新蛇头的位置 $(tx, ty)$。需要确保整条蛇没有越界,没有碰到障碍物,并且旋转转移时,额外检查 $(x + 1, y + 1)$ 位置是否合法。 - -代码: +Java 代码: ```Java class Solution { int[][] dirs = new int[][]{{1,0,0},{0,1,0},{0,0,1}}; @@ -105,6 +106,85 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int minimumMoves(vector>& g) { + vector> dirs = {{1,0,0}, {0,1,0}, {0,0,1}}; + int n = g.size(); + queue> d; + d.push({0, 0, 0, 0}); + vector>> vis(n, vector>(n, vector(2, false))); + vis[0][0][0] = true; + while (!d.empty()) { + vector info = d.front(); + d.pop(); + int x = info[0], y = info[1], cd = info[2], step = info[3]; + for (vector& dir : dirs) { + int nx = x + dir[0], ny = y + dir[1], nd = cd ^ dir[2]; + int tx = nd == 0 ? nx : nx + 1, ty = nd == 0 ? ny + 1 : ny; + if (nx >= n || ny >= n || tx >= n || ty >= n) continue; + if (g[nx][ny] == 1 || g[tx][ty] == 1) continue; + if (vis[nx][ny][nd]) continue; + if (cd != nd && g[x + 1][y + 1] == 1) continue; + if (nx == n - 1 && ny == n - 2 && nd == 0) return step + 1; + d.push({nx, ny, nd, step + 1}); + vis[nx][ny][nd] = true; + } + } + return -1; + } +}; +``` +Python 代码: +```Python +class Solution: + def minimumMoves(self, g: List[List[int]]) -> int: + dirs = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] + n = len(g) + d = deque([(0,0,0,0)]) + vis = [[[0]*2 for _ in range(n)] for _ in range(n)] + vis[0][0][0] = 1 + while d: + x, y, cd, step = d.popleft() + for dir in dirs: + nx, ny, nd = x + dir[0], y + dir[1], cd ^ dir[2] + tx, ty = nx + (nd == 1), ny + (nd == 0) + if nx >= n or ny >= n or tx >= n or ty >= n: continue + if g[nx][ny] == 1 or g[tx][ty] == 1: continue + if vis[nx][ny][nd]: continue + if cd != nd and g[x + 1][y + 1] == 1: continue + if nx == n - 1 and ny == n - 2 and nd == 0: return step + 1 + d.append((nx, ny, nd, step + 1)) + vis[nx][ny][nd] = 1 + return -1 +``` +TypeScript 代码: +```TypeScript +function minimumMoves(g: number[][]): number { + const n = g.length; + const d: [number, number, number, number][] = [[0,0,0,0]]; + const vis: boolean[][][] = Array.from({ length: n }, () => Array.from({ length: n }, () => [false, false])); + vis[0][0][0] = true; + const dirs: [number, number, number][] = [[1,0,0], [0,1,0], [0,0,1]]; + while (d.length > 0) { + const [x, y, cd, step] = d.shift()!; + for (const dir of dirs) { + const nx = x + dir[0], ny = y + dir[1], nd = cd ^ dir[2]; + const tx = nd === 0 ? nx : nx + 1, ty = nd === 0 ? ny + 1 : ny; + if (nx >= n || ny >= n || tx >= n || ty >= n) continue; + if (g[nx][ny] === 1 || g[tx][ty] === 1) continue + if (vis[nx][ny][nd]) continue; + if (cd !== nd && g[x + 1][y + 1] === 1) continue; + if (nx === n - 1 && ny === n - 2 && nd === 0) return step + 1; + d.push([nx, ny, nd, step + 1]); + vis[nx][ny][nd] = true; + } + } + return -1; +}; +``` * 时间复杂度:$O(n^2)$ * 空间复杂度:$O(n^2 \times C)$,其中 $C = 2$ 代表蛇可变状态方向 diff --git "a/LeetCode/1221-1230/1222. \345\217\257\344\273\245\346\224\273\345\207\273\345\233\275\347\216\213\347\232\204\347\232\207\345\220\216\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1221-1230/1222. \345\217\257\344\273\245\346\224\273\345\207\273\345\233\275\347\216\213\347\232\204\347\232\207\345\220\216\357\274\210\344\270\255\347\255\211\357\274\211.md" index c22a0b3d..dbfbd16f 100644 --- "a/LeetCode/1221-1230/1222. \345\217\257\344\273\245\346\224\273\345\207\273\345\233\275\347\216\213\347\232\204\347\232\207\345\220\216\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1221-1230/1222. \345\217\257\344\273\245\346\224\273\345\207\273\345\233\275\347\216\213\347\232\204\347\232\207\345\220\216\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -48,9 +48,9 @@ Tag : 「模拟」、「BFS」 提示: * $1 <= queens.length <= 63$ -* $queens[i].length == 2$ +* $queens[i].length = 2$ * $0 <= queens[i][j] < 8$ -* $king.length == 2$ +* $king.length = 2$ * $0 <= king[0], king[1] < 8$ * 一个棋盘格上最多只能放置一枚棋子。 @@ -82,7 +82,9 @@ class Solution { checked[i] = true; } else { if (!vis[nx][ny]) continue; - add(ans, nx, ny); + List list = new ArrayList<>(); + list.add(nx); list.add(ny); + ans.add(list); checked[i] = true; } } @@ -90,13 +92,89 @@ class Solution { } return ans; } - void add(List> ans, int x, int y) { - List list = new ArrayList<>(); - list.add(x); list.add(y); - ans.add(list); - } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector> queensAttacktheKing(vector>& queens, vector& king) { + vector> dirs {{1,0},{0,1},{0,-1},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}}; + vector> ans; + vector> vis(8, vector(8, false)); + for (auto& queen : queens) vis[queen[0]][queen[1]] = true; + int x = king[0], y = king[1], step = 1; + vector checked(8, false); + while (step <= 8) { + for (int i = 0; i < 8; i++) { + if (checked[i]) continue; + int nx = x + step * dirs[i][0]; + int ny = y + step * dirs[i][1]; + if (nx < 0 || nx >= 8 || ny < 0 || ny >= 8) { + checked[i] = true; + } else { + if (!vis[nx][ny]) continue; + ans.push_back({nx, ny}); + checked[i] = true; + } + } + step++; + } + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def queensAttacktheKing(self, queens: List[List[int]], king: List[int]) -> List[List[int]]: + dirs = [[1,0],[0,1],[0,-1],[-1,0],[1,1],[-1,-1],[1,-1],[-1,1]] + vis = [[False] * 8 for _ in range(8)] + for q in queens: + vis[q[0]][q[1]] = True + x, y = king + ans = [] + checked = [False] * 8 + step = 1 + while step <= 8: + for i in range(8): + if checked[i]: continue + nx, ny = x + dirs[i][0] * step, y + dirs[i][1] * step + if nx < 0 or nx >= 8 or ny < 0 or ny >= 8: + checked[i] = True + else: + if not vis[nx][ny]: continue + ans.append([nx, ny]) + checked[i] = True + step += 1 + return ans +``` +TypeScript 代码: +```TypeScript +function queensAttacktheKing(queens: number[][], king: number[]): number[][] { + let dirs = [[1,0],[0,1],[0,-1],[-1,0],[1,1],[-1,-1],[1,-1],[-1,1]]; + let vis: boolean[][] = Array.from({length:8},()=>Array(8).fill(false)); + for (let q of queens) vis[q[0]][q[1]] = true; + let x = king[0], y = king[1], step = 1; + let ans: number[][] = []; + let checked: boolean[] = Array(8).fill(false); + while (step <= 8) { + for (let i = 0; i < 8; i++) { + if (checked[i]) continue; + let nx = x + dirs[i][0] * step, ny = y + dirs[i][1] * step; + if (nx < 0 || nx >= 8 || ny < 0 || ny >= 8) { + checked[i] = true; + } else { + if (!vis[nx][ny]) continue; + ans.push([nx, ny]); + checked[i] = true; + } + } + step++; + } + return ans; +}; +``` * 时间复杂度:$O(C)$,其中 $C = 8 \times 8$ 为棋盘总大小 * 空间复杂度:$O(C)$,其中 $C = 8 \times 8$ 为棋盘总大小 @@ -109,8 +187,6 @@ class Solution { 相比于直接模拟,`BFS` 无须使用额外变量记录处理过的方向以及当前位置与国王的距离。 Java 代码: - - ```Java class Solution { int[][] dirs = new int[][]{{1,0},{0,1},{0,-1},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}}; @@ -141,6 +217,87 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector> queensAttacktheKing(vector>& queens, vector& king) { + vector> dirs = {{1,0},{0,1},{0,-1},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}}; + vector> vis(8, vector(8, false)); + for (vector& queen : queens) vis[queen[0]][queen[1]] = true; + deque> d; + for (int i = 0; i < 8; i++) { + int x = king[0] + dirs[i][0], y = king[1] + dirs[i][1]; + if (x < 0 || x >= 8 || y < 0 || y >= 8) continue; + d.push_back({x, y, i}); + } + vector> res; + while (!d.empty()) { + vector cur = d.front(); + d.pop_front(); + if (vis[cur[0]][cur[1]]) { + res.push_back({cur[0], cur[1]}); + } else { + int nx = cur[0] + dirs[cur[2]][0], ny = cur[1] + dirs[cur[2]][1]; + if (nx < 0 || nx >= 8 || ny < 0 || ny >= 8) continue; + d.push_back({nx, ny, cur[2]}); + } + } + return res; + } +}; +``` +Python 代码: +```Python +class Solution: + def queensAttacktheKing(self, queens, king): + dirs = [[1,0],[0,1],[0,-1],[-1,0],[1,1],[-1,-1],[1,-1],[-1,1]] + vis = [[False]*8 for _ in range(8)] + for q in queens: vis[q[0]][q[1]] = True + d = deque() + for i in range(8): + x = king[0] + dirs[i][0] + y = king[1] + dirs[i][1] + if x < 0 or x >= 8 or y < 0 or y >= 8: continue + d.append([x, y, i]) + ans = [] + while d: + cur = d.popleft() + if vis[cur[0]][cur[1]]: + ans.append([cur[0], cur[1]]) + else: + x = cur[0] + dirs[cur[2]][0] + y = cur[1] + dirs[cur[2]][1] + if x < 0 or x >= 8 or y < 0 or y >= 8: continue + d.append([x, y, cur[2]]) + return ans +``` +TypeScript 代码: +```TypeScript +function queensAttacktheKing(queens: number[][], king: number[]): number[][] { + let dirs = [[1,0],[0,1],[0,-1],[-1,0],[1,1],[-1,-1],[1,-1],[-1,1]]; + let vis: boolean[][] = Array(8).fill(false).map(() => Array(8).fill(false)); + queens.forEach(q => vis[q[0]][q[1]] = true); + let d: number[][] = []; + for (let i = 0; i < 8; i++) { + let x = king[0] + dirs[i][0], y = king[1] + dirs[i][1]; + if (x < 0 || x >= 8 || y < 0 || y >= 8) continue; + d.push([x, y, i]); + } + let res = []; + while (d.length !== 0) { + let cur = d.shift(); + if (vis[cur[0]][cur[1]]) { + res.push([cur[0], cur[1]]); + } else { + let x = cur[0] + dirs[cur[2]][0], y = cur[1] + dirs[cur[2]][1]; + if (x < 0 || x >= 8 || y < 0 || y >= 8) continue; + d.push([x, y, cur[2]]); + } + } + return res; +}; +``` * 时间复杂度:$O(C)$,其中 $C = 4 \times 8$ 为四条线的总步数 * 空间复杂度:$O(C)$,其中 $C = 8 \times 8$ 为棋盘总大小 diff --git "a/LeetCode/1231-1240/1235. \350\247\204\345\210\222\345\205\274\350\201\214\345\267\245\344\275\234\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1231-1240/1235. \350\247\204\345\210\222\345\205\274\350\201\214\345\267\245\344\275\234\357\274\210\345\233\260\351\232\276\357\274\211.md" index 629c76f8..1cd3117d 100644 --- "a/LeetCode/1231-1240/1235. \350\247\204\345\210\222\345\205\274\350\201\214\345\267\245\344\275\234\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1231-1240/1235. \350\247\204\345\210\222\345\205\274\350\201\214\345\267\245\344\275\234\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -59,7 +59,7 @@ Tag : 「序列 DP」、「二分」、「排序」 我们知道,在理想情况下,若能将所有工作排成不重叠的直线,我们便能通过完成所有工作来取得最大收益。 -![image.png](https://pic.leetcode.cn/1666400800-lPFoHa-image.png) +![](https://pic.leetcode.cn/1666400800-lPFoHa-image.png) 归结到每个工作,我们总有「选择完成该工作」和「选择不完成该工作」两种决策。 @@ -76,7 +76,7 @@ Tag : 「序列 DP」、「二分」、「排序」 **当我们处理到 $job[i]$ 时,为了能够「将所有所能拼接在 $job[i]$ 前面的 $job[j]$ 归结到一边」并且「所能更新 $f[i]$ 的 $f[j]$ 均被计算」,我们可以通过对所有的 $job[i]$ 进行右端点(结束时间)进行排升序,并按照从小到大的方式处理每个 $job[i]$。** -![image.png](https://pic.leetcode.cn/1666401661-okRwsD-image.png) +![](https://pic.leetcode.cn/1666401661-okRwsD-image.png) 此处排序的意义有两点: @@ -108,28 +108,30 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function jobScheduling(st: number[], et: number[], ps: number[]): number { - const n = st.length - const list = new Array>() - for (let i = 0; i < n; i++) list.push([st[i], et[i], ps[i]]) - list.sort((a,b)=>a[1]-b[1]) - const f = new Array(n + 10).fill(0) - for (let i = 1; i <= n; i++) { - const info = list[i - 1] - const a = info[0], b = info[1], c = info[2] - f[i] = Math.max(f[i - 1], c) - let l = 0, r = i - 1 - while (l < r) { - const mid = l + r + 1 >> 1 - if (list[mid][1] <= a) l = mid - else r = mid - 1 +C++ 代码: +```C++ +class Solution { +public: + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + int n = startTime.size(); + vector> list(n); + for (int i = 0; i < n; i++) list[i] = {startTime[i], endTime[i], profit[i]}; + sort(list.begin(), list.end(), [](vector a, vector b)->bool{return a[1] < b[1];}); + vector f(n + 10, 0); + for(int i = 1; i <= n; i++) { + int a = list[i - 1][0], b = list[i - 1][1], c = list[i - 1][2]; + f[i] = max(f[i - 1], c); + int l = 0, r = i - 1; + while (l < r) { + int mid = l + r + 1 >> 1; + if (list[mid][1] <= a) l = mid; + else r = mid - 1; + } + if (list[r][1] <= a) f[i] = max(f[i], f[r + 1] + c); } - if (list[r][1] <= a) f[i] = Math.max(f[i], f[r + 1] + c) + return f[n]; } - return f[n] -} +}; ``` Python 代码: ```Python @@ -153,6 +155,29 @@ class Solution: f[i] = max(f[i], f[r + 1] + c) return f[n] ``` +TypeScript 代码: +```TypeScript +function jobScheduling(st: number[], et: number[], ps: number[]): number { + const n = st.length + const list = new Array>() + for (let i = 0; i < n; i++) list.push([st[i], et[i], ps[i]]) + list.sort((a,b)=>a[1]-b[1]) + const f = new Array(n + 10).fill(0) + for (let i = 1; i <= n; i++) { + const info = list[i - 1] + const a = info[0], b = info[1], c = info[2] + f[i] = Math.max(f[i - 1], c) + let l = 0, r = i - 1 + while (l < r) { + const mid = l + r + 1 >> 1 + if (list[mid][1] <= a) l = mid + else r = mid - 1 + } + if (list[r][1] <= a) f[i] = Math.max(f[i], f[r + 1] + c) + } + return f[n] +} +``` * 时间复杂度:排序复杂度为 $O(n\log{n})$;`DP` 过程共有 $n$ 个状态需要转移,每次转移需要进行二分,单次复杂度为 $O(\log{n})$。整体复杂度为 $O(n\log{n})$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225\357\274\210\344\270\255\347\255\211\357\274\211.md" index 2bf7d947..06a25197 100644 --- "a/LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,12 +6,12 @@ Tag : 「贪心」、「模拟」 -矩形蛋糕的高度为 `h` 且宽度为 `w`,给你两个整数数组 `horizontalCuts` 和 `verticalCuts`,其中: +矩形蛋糕的高度为 `h` 且宽度为 `w`,给你两个整数数组 `hs` 和 `vs`,其中: -* `horizontalCuts[i]` 是从矩形蛋糕顶部到第 `i` 个水平切口的距离 -* `verticalCuts[j]` 是从矩形蛋糕的左侧到第 `j` 个竖直切口的距离 +* `hs[i]` 是从矩形蛋糕顶部到第 `i` 个水平切口的距离 +* `vs[j]` 是从矩形蛋糕的左侧到第 `j` 个竖直切口的距离 -请你按数组 `horizontalCuts` 和 `verticalCuts` 中提供的水平和竖直位置切割后,请你找出**面积最大**的那份蛋糕,并返回其**面积**。 +请你按数组 `hs` 和 `vs` 中提供的水平和竖直位置切割后,请你找出**面积最大**的那份蛋糕,并返回其**面积**。 由于答案可能是一个很大的数字,因此需要将结果 对 $10^9 + 7$ 取余 后返回。 @@ -19,7 +19,7 @@ Tag : 「贪心」、「模拟」 ![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/05/30/leetcode_max_area_2.png) ``` -输入:h = 5, w = 4, horizontalCuts = [1,2,4], verticalCuts = [1,3] +输入:h = 5, w = 4, hs = [1,2,4], vs = [1,3] 输出:4 @@ -27,8 +27,9 @@ Tag : 「贪心」、「模拟」 ``` 示例 2: ![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/05/30/leetcode_max_area_3.png) + ``` -输入:h = 5, w = 4, horizontalCuts = [3,1], verticalCuts = [1] +输入:h = 5, w = 4, hs = [3,1], vs = [1] 输出:6 @@ -36,26 +37,24 @@ Tag : 「贪心」、「模拟」 ``` 示例 3: ``` -输入:h = 5, w = 4, horizontalCuts = [3], verticalCuts = [3] +输入:h = 5, w = 4, hs = [3], vs = [3] 输出:9 ``` 提示: * $2 <= h, w <= 10^9$ -* $1 <= horizontalCuts.length <= \min(h - 1, 10^5)$ -* $1 <= verticalCuts.length <= \min(w - 1, 10^5)$ -* $1 <= horizontalCuts[i] < h$ -* $1 <= verticalCuts[i] < w$ -* 题目数据保证 `horizontalCuts` 中的所有元素各不相同 -* 题目数据保证 `verticalCuts` 中的所有元素各不相同 +* $1 <= hs.length <= \min(h - 1, 10^5)$ +* $1 <= vs.length <= \min(w - 1, 10^5)$ +* $1 <= hs[i] < h$ +* $1 <= vs[i] < w$ +* 题目数据保证 `hs` 中的所有元素各不相同 +* 题目数据保证 `vs` 中的所有元素各不相同 --- ### 贪心 -为了方便,记 `horizontalCuts` 为 `hs`,记 `verticalCuts` 为 `vs`。 - 由于求是“最大”蛋糕面积,**水平/垂直方向的连续段必然由「同方向且相邻」的切割位置(或是蛋糕边界)所构成**。 这点可通过反证法证明:如果最终蛋糕的(左右或上下)边缘不是由「相邻」的切割位置(或是蛋糕边界)决定,而是由跨越某些切割点的位置所决定的话,那么这个蛋糕必不是“完整”一块。 @@ -86,21 +85,6 @@ class Solution { } } ``` -Python 代码: -```Python -class Solution: - def maxArea(self, h: int, w: int, hs: List[int], vs: List[int]) -> int: - MOD = 10 ** 9 + 7 - hs.sort() - vs.sort() - n, m = len(hs), len(vs) - mh, mv = max(hs[0], h - hs[n - 1]), max(vs[0], w - vs[m - 1]) - for i in range(1, n): - mh = max(mh, hs[i] - hs[i - 1]) - for i in range(1, m): - mv = max(mv, vs[i] - vs[i - 1]) - return (mh * mv) % MOD -``` C++ 代码: ```C++ class Solution { @@ -117,6 +101,21 @@ public: } }; ``` +Python 代码: +```Python +class Solution: + def maxArea(self, h: int, w: int, hs: List[int], vs: List[int]) -> int: + MOD = 10 ** 9 + 7 + hs.sort() + vs.sort() + n, m = len(hs), len(vs) + mh, mv = max(hs[0], h - hs[n - 1]), max(vs[0], w - vs[m - 1]) + for i in range(1, n): + mh = max(mh, hs[i] - hs[i - 1]) + for i in range(1, m): + mv = max(mv, vs[i] - vs[i - 1]) + return (mh * mv) % MOD +``` TypeScript 代码: ```TypeScript function maxArea(h: number, w: number, hs: number[], vs: number[]): number { diff --git "a/LeetCode/1761-1770/1766. \344\272\222\350\264\250\346\240\221\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1761-1770/1766. \344\272\222\350\264\250\346\240\221\357\274\210\345\233\260\351\232\276\357\274\211.md" index a01884f7..b9614810 100644 --- "a/LeetCode/1761-1770/1766. \344\272\222\350\264\250\346\240\221\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1761-1770/1766. \344\272\222\350\264\250\346\240\221\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -7,55 +7,61 @@ Tag : 「DFS」 -给你一个 n 个节点的树(也就是一个无环连通无向图),节点编号从 0 到 n - 1 ,且恰好有 n - 1 条边,每个节点有一个值。树的 根节点 为 0 号点。 +给你一个 `n` 个节点的树(也就是一个无环连通无向图),节点编号从 `0` 到 `n - 1`,且恰好有 `n - 1` 条边,每个节点有一个值,树的根节点为 `0` 号点。 -给你一个整数数组 nums 和一个二维数组 edges 来表示这棵树。nums[i] 表示第 i 个点的值,edges[j] = [uj, vj] 表示节点 uj 和节点 vj 在树中有一条边。 +给你一个整数数组 `nums` 和一个二维数组 `edges` 来表示这棵树。 -当 gcd(x, y) == 1 ,我们称两个数 x 和 y 是 互质的 ,其中 gcd(x, y) 是 x 和 y 的 最大公约数 。 +`nums[i]` 表示第 `i` 个点的值,$edges[j] = [u_{j}, v_{j}]$ 表示节点 $u_{j}$ 和节点 $v_{j}$ 在树中有一条边。 -从节点 i 到 根 最短路径上的点都是节点 i 的祖先节点。一个节点 不是 它自己的祖先节点。 +当 `gcd(x, y) == 1`,我们称两个数 `x` 和 `y` 是 互质的 ,其中 `gcd(x, y)` 是 `x` 和 `y` 的最大公约数。 -请你返回一个大小为 n 的数组 ans ,其中 ans[i]是离节点 i 最近的祖先节点且满足 nums[i] 和 nums[ans[i]] 是 互质的 ,如果不存在这样的祖先节点,ans[i] 为 -1 。 +从节点 `i` 到根最短路径上的点都是节点 `i` 的祖先节点,一个节点不是它自己的祖先节点。 + +请你返回一个大小为 `n` 的数组 `ans`,其中 `ans[i]` 是离节点 `i` 最近的祖先节点且满足 `nums[i]` 和 `nums[ans[i]]` 是互质的,如果不存在这样的祖先节点,`ans[i]` 为 `-1`。 示例 1: ![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2021/02/20/untitled-diagram.png) ``` 输入:nums = [2,3,3,2], edges = [[0,1],[1,2],[1,3]] + 输出:[-1,0,0,1] + 解释:上图中,每个节点的值在括号中表示。 - 节点 0 没有互质祖先。 - 节点 1 只有一个祖先节点 0 。它们的值是互质的(gcd(2,3) == 1)。 - 节点 2 有两个祖先节点,分别是节点 1 和节点 0 。节点 1 的值与它的值不是互质的(gcd(3,3) == 3)但节点 0 的值是互质的(gcd(2,3) == 1),所以节点 0 是最近的符合要求的祖先节点。 - 节点 3 有两个祖先节点,分别是节点 1 和节点 0 。它与节点 1 互质(gcd(3,2) == 1),所以节点 1 是离它最近的符合要求的祖先节点。 ``` + 示例 2: ![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2021/02/20/untitled-diagram1.png) ``` 输入:nums = [5,6,10,2,3,6,15], edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6]] + 输出:[-1,0,-1,0,0,0,-1] ``` 提示: -* nums.length == n -* 1 <= nums[i] <= 50 -* 1 <= n <= $10^5$ -* edges.length == n - 1 -* edges[j].length == 2 -* 0 <= uj, vj < n -* uj != vj +* $nums.length = n$ +* $1 <= nums[i] <= 50$ +* $1 <= n <= 10^5$ +* $edges.length = n - 1$ +* $edges[j].length = 2$ +* $0 <= u_{j}, v_{j} < n$ +* $u_{j} \neq v_{j}$ --- -### 基本思路 +### DFS 题目描述很长,但其实就是说每个节点从下往上找,找到最近的「与其互质」的节点。 数据范围是 $10^5$,如果每个节点都直接往上找最近「互质」祖宗节点的话,当树为线性时,复杂度是 $O(n^2)$ ,会超时。 -因此我们要利用 nums[i] 范围只有 50 的特性。 +因此我们要利用 $nums[i]$ 范围只有 $50$ 的特性。 -我们可以先预处理除 [1, 50] 范围内的每个数,求出他们互质的数有哪些,存到一个字典里。 +我们可以先预处理除 $[1, 50]$ 范围内的每个数,求出他们互质的数有哪些,存到一个字典里。 那么对于某个节点而言,假设节点的值为 `x` ,所在层数为 `y`。 @@ -63,12 +69,7 @@ Tag : 「DFS」 用 `dep[x]` 表示距离值为 `x` 的节点最近的层是多少;`pos[x]` 代表具体的节点编号。 -*** - -### DFS 解法 - 代码: - ```java class Solution { int[] ans; diff --git "a/LeetCode/1781-1790/1781. \346\211\200\346\234\211\345\255\220\345\255\227\347\254\246\344\270\262\347\276\216\344\270\275\345\200\274\344\271\213\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1781-1790/1781. \346\211\200\346\234\211\345\255\220\345\255\227\347\254\246\344\270\262\347\276\216\344\270\275\345\200\274\344\271\213\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" index d37a8e28..1ed63af1 100644 --- "a/LeetCode/1781-1790/1781. \346\211\200\346\234\211\345\255\220\345\255\227\347\254\246\344\270\262\347\276\216\344\270\275\345\200\274\344\271\213\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1781-1790/1781. \346\211\200\346\234\211\345\255\220\345\255\227\347\254\246\344\270\262\347\276\216\344\270\275\345\200\274\344\271\213\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -1,6 +1,6 @@ ### 题目描述 -这是 LeetCode 上的 **[1781. 所有子字符串美丽值之和](https://acoier.com/2022/12/12/1780.%20%E5%88%A4%E6%96%AD%E4%B8%80%E4%B8%AA%E6%95%B0%E5%AD%97%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E8%A1%A8%E7%A4%BA%E6%88%90%E4%B8%89%E7%9A%84%E5%B9%82%E7%9A%84%E5%92%8C%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/)** ,难度为 **中等**。 +这是 LeetCode 上的 **[1781. 所有子字符串美丽值之和]()** ,难度为 **中等**。 Tag : 「模拟」、「哈希表」 @@ -70,29 +70,30 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function beautySum(s: string): number { - let n = s.length, ans = 0 - for (let i = 0; i < n; i++) { - const cnts = new Array(26).fill(0) - const map = new Map() - let min = 0, max = 0 - for (let j = i; j < n; j++) { - const c = s.charCodeAt(j) - 'a'.charCodeAt(0) - if (!map.has(cnts[c])) map.set(cnts[c], 0) - map.set(cnts[c], map.get(cnts[c]) - 1) - if (!map.has(cnts[c] + 1)) map.set(cnts[c] + 1, 0) - map.set(cnts[c] + 1, map.get(cnts[c] + 1) + 1) - cnts[c]++ - if (cnts[c] == 1) min = 1 - else if (map.get(min) <= 0) min++ - max = Math.max(max, cnts[c]) - ans += max - min +C++ 代码: +```C++ +class Solution { +public: + int beautySum(string s) { + int n = s.size(), cnts[26], ans = 0; + unordered_map map; + for(int i = 0; i < n; ++i) { + memset(cnts, 0, sizeof(cnts)); + map.clear(); + int min = -1, maxv = -1; + for(int j = i; j < n; ++j) { + int c = s[j] - 'a'; + map[cnts[c]]--; map[cnts[c] + 1]++; + cnts[c]++; + if(cnts[c] == 1) min = 1; + else if(map[min] <= 0) min++; + maxv = max(maxv, cnts[c]); + ans += maxv - min; + } } + return ans; } - return ans -} +}; ``` Python 代码: ```Python @@ -116,6 +117,30 @@ class Solution: ans += maxv - minv return ans ``` +TypeScript 代码: +```TypeScript +function beautySum(s: string): number { + let n = s.length, ans = 0 + for (let i = 0; i < n; i++) { + const cnts = new Array(26).fill(0) + const map = new Map() + let min = 0, max = 0 + for (let j = i; j < n; j++) { + const c = s.charCodeAt(j) - 'a'.charCodeAt(0) + if (!map.has(cnts[c])) map.set(cnts[c], 0) + map.set(cnts[c], map.get(cnts[c]) - 1) + if (!map.has(cnts[c] + 1)) map.set(cnts[c] + 1, 0) + map.set(cnts[c] + 1, map.get(cnts[c] + 1) + 1) + cnts[c]++ + if (cnts[c] == 1) min = 1 + else if (map.get(min) <= 0) min++ + max = Math.max(max, cnts[c]) + ans += max - min + } + } + return ans +} +``` * 时间复杂度:$O(n^2)$ * 空间复杂度:$O(C)$,其中 $C = 26$ 为字符集大小 diff --git "a/LeetCode/231-240/235. \344\272\214\345\217\211\346\220\234\347\264\242\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/235. \344\272\214\345\217\211\346\220\234\347\264\242\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 5703bc2c..41e65419 100644 --- "a/LeetCode/231-240/235. \344\272\214\345\217\211\346\220\234\347\264\242\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/235. \344\272\214\345\217\211\346\220\234\347\264\242\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" @@ -42,7 +42,7 @@ Tag : 「二叉树」、「DFS」、「递归」 ### DFS -也是常见的 `LCA` 问题,但相比 [236. 二叉树的最近公共祖先](),本题搜索对象为二叉搜索树,利用此特性,我们可以将搜索复杂度从 $O(n)$ 优化至 $O(h)$。 +也是常见的 `LCA` 问题,但相比 [236. 二叉树的最近公共祖先](https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&mid=2247500218&idx=1&sn=a6d790dcecfee353be5f3b53c312c3d4&chksm=fd9f6aa5cae8e3b36d85448674b189ed2d35fdce18381ac7676ec90a33d62da05718f85e3103#rd),本题搜索对象为二叉搜索树,利用此特性,我们可以将搜索复杂度从 $O(n)$ 优化至 $O(h)$。 利用原函数作为递归函数,复用 `root` 作为搜索过程中的当前节点,根据 `root` 和两节点关系进行分情况讨论: diff --git "a/LeetCode/2331-2340/2335. \350\243\205\346\273\241\346\235\257\345\255\220\351\234\200\350\246\201\347\232\204\346\234\200\347\237\255\346\200\273\346\227\266\351\225\277\357\274\210\347\256\200\345\215\225\357\274\211.md" "b/LeetCode/2331-2340/2335. \350\243\205\346\273\241\346\235\257\345\255\220\351\234\200\350\246\201\347\232\204\346\234\200\347\237\255\346\200\273\346\227\266\351\225\277\357\274\210\347\256\200\345\215\225\357\274\211.md" index 975b5706..a4e08eef 100644 --- "a/LeetCode/2331-2340/2335. \350\243\205\346\273\241\346\235\257\345\255\220\351\234\200\350\246\201\347\232\204\346\234\200\347\237\255\346\200\273\346\227\266\351\225\277\357\274\210\347\256\200\345\215\225\357\274\211.md" +++ "b/LeetCode/2331-2340/2335. \350\243\205\346\273\241\346\235\257\345\255\220\351\234\200\350\246\201\347\232\204\346\234\200\347\237\255\346\200\273\346\227\266\351\225\277\357\274\210\347\256\200\345\215\225\357\274\211.md" @@ -61,7 +61,7 @@ Tag : 「排序」、「递归」、「模拟」、「贪心」、「数学」 为了尽可能的凑成多的对数,我们可以每次取剩余数量最多且不为 `0` 的两类水进行成组(因此每次处理前需要先对当前 `amount` 进行排序),直到没有水剩余,或只有一类水的剩余数据量不为 `0`(剩下的水只能独自生成)。 -代码: +Java 代码: ```Java class Solution { public int fillCups(int[] amount) { @@ -72,6 +72,39 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int fillCups(vector& amount) { + sort(amount.begin(), amount.end()); + if (amount[1] == 0) return amount[2]; + amount[1]--; amount[2]--; + return 1 + fillCups(amount); + } +}; +``` +Python 代码: +```Python +class Solution: + def fillCups(self, amount: List[int]) -> int: + amount.sort() + if amount[1] == 0: + return amount[2] + amount[1] -= 1 + amount[2] -= 1 + return 1 + self.fillCups(amount) +``` +TypeScript 代码: +```TypeScript +function fillCups(amount: number[]): number { + amount.sort((a, b) => a - b); + if (amount[1] === 0) return amount[2]; + amount[1] -= 1; + amount[2] -= 1; + return 1 + fillCups(amount); +}; +``` * 时间复杂度:由于 `amount` 的长度固定为 `3`,因此排序消耗可视为常量;每次至少会消耗两杯水,直到递归结束或只剩下一种水。复杂度为 $O(\sum_{i = 0}^{2} amount[i])$ * 空间复杂度:忽略递归和排序带来的额外空间开销,复杂度为 $O(1)$ @@ -95,7 +128,7 @@ class Solution { 最后,为了处理 $t$ 的奇偶性问题,先用 $a$ 和 $b$ 进行 $\left \lceil \frac{a + b - c}{2} \right \rceil$ 抵消操作,再与 $c$ 进行抵消 -代码: +Java 代码: ```Java class Solution { public int fillCups(int[] amount) { @@ -106,7 +139,39 @@ class Solution { } } ``` -* 时间复杂度:$O(1)$ +C++ 代码: +```C++ +class Solution { +public: + int fillCups(vector& amount) { + sort(amount.begin(), amount.end()); + int a = amount[0], b = amount[1], c = amount[2]; + if (a + b <= c) return c; + else return (a + b - c + 1) / 2 + c; + } +}; +``` +Python 代码: +```Python +class Solution: + def fillCups(self, amount: List[int]) -> int: + amount.sort() + a, b, c = amount + if a + b <= c: + return c + else: + return (a + b - c + 1) // 2 + c +``` +TypeScript 代码: +```TypeScript +function fillCups(amount: number[]): number { + amount.sort((a, b) => a - b); + const [a, b, c] = amount; + if (a + b <= c) return c; + else return Math.floor((a + b - c + 1) / 2) + c; +}; +``` +* 时间复杂度:由于 `amount` 的长度固定为 `3`,因此排序消耗可视为常量,整体复杂度为 $O(1)$ * 空间复杂度:$O(1)$ --- diff --git "a/LeetCode/2331-2340/2336. \346\227\240\351\231\220\351\233\206\344\270\255\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/2331-2340/2336. \346\227\240\351\231\220\351\233\206\344\270\255\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" index dfbf2e11..64ed400b 100644 --- "a/LeetCode/2331-2340/2336. \346\227\240\351\231\220\351\233\206\344\270\255\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/2331-2340/2336. \346\227\240\351\231\220\351\233\206\344\270\255\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -141,6 +141,33 @@ class SmallestInfiniteSet: heapq.heappush(self.q, x) self.vis[x] = True ``` +TypeScript 代码: +```TypeScript +class SmallestInfiniteSet { + vis: boolean[] = Array(1010).fill(false); + q: number[] = []; + idx: number = 1; + popSmallest(): number { + let ans: number = -1; + if (this.q.length !== 0) { + ans = this.q.sort((a, b) => a - b).shift() as number; + this.vis[ans] = false; + } else { + ans = this.idx++; + } + return ans; + } + addBack(x: number): void { + if (x >= this.idx || this.vis[x]) return; + if (x == this.idx - 1) { + this.idx--; + } else { + this.q.push(x); + this.vis[x] = true; + } + } +} +``` * 时间复杂度:插入和取出的最坏复杂度为 $O(\log{n})$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/581-590/583. \344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/581-590/583. \344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234\357\274\210\344\270\255\347\255\211\357\274\211.md" index 1c9ba7e6..adad1af0 100644 --- "a/LeetCode/581-590/583. \344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/581-590/583. \344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,7 +6,7 @@ Tag : 「最长公共子序列」、「序列 DP」 -给定两个单词 `word1` 和 `word2`,找到使得 `word1` 和 `word2` 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 +给定两个单词 `s1` 和 `s2`,找到使得 `s1` 和 `s2` 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 示例: @@ -49,7 +49,7 @@ Tag : 「最长公共子序列」、「序列 DP」 通常会习惯性往字符串头部追加一个空格,以减少边界判断(使下标从 1 开始,并很容易构造出可滚动的「有效值」)。但实现上,不用真的往字符串中最佳空格,只需在初始化动规值时假定存在首部空格,以及对最后的 LCS 长度进行减一操作即可。 -代码: +Java 代码: ```Java class Solution { public int minDistance(String s1, String s2) { @@ -70,6 +70,57 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int minDistance(string s1, string s2) { + int n = s1.size(), m = s2.size(); + vector> f(n + 1, vector(m + 1)); + for (int i = 0; i <= n; i++) f[i][0] = 1; + for (int j = 0; j <= m; j++) f[0][j] = 1; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + f[i][j] = max(f[i - 1][j], f[i][j - 1]); + if (s1[i - 1] == s2[j - 1]) f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1); + } + } + int max = f[n][m] - 1; + return n - max + m - max; + } +}; +``` +Python 代码: +```Python +class Solution: + def minDistance(self, s1: str, s2: str) -> int: + n, m = len(s1), len(s2) + f = [[1]* (m + 1) for _ in range(n + 1)] + for i in range(1, n + 1): + for j in range(1, m + 1): + f[i][j] = max(f[i - 1][j], f[i][j - 1]) + if s1[i - 1] == s2[j - 1]: + f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1) + max_val = f[n][m] - 1 + return n - max_val + m - max_val +``` +TypeScript 代码: +```TypeScript +function minDistance(s1: string, s2: string): number { + const n = s1.length, m = s2.length; + const f: number[][] = Array(n + 1).fill(0).map(() => Array(m + 1).fill(1)); + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= m; j++) { + f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]); + if (s1[i - 1] === s2[j - 1]) { + f[i][j] = Math.max(f[i][j], f[i - 1][j - 1] + 1); + } + } + } + const max = f[n][m] - 1; + return n - max + m - max; +}; +``` * 时间复杂度:$O(n \times m)$ * 空间复杂度:$O(n \times m)$ @@ -88,7 +139,7 @@ class Solution { $f[i][j]$ 为上述方案中的最小值,最终答案为 $f[n][m]$。 -代码: +Java 代码: ```Java class Solution { public int minDistance(String s1, String s2) { @@ -107,6 +158,58 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int minDistance(string s1, string s2) { + int n = s1.size(), m = s2.size(); + vector> f(n + 1, vector(m + 1)); + for(int i = 0; i <= n; i++) f[i][0] = i; + for(int j = 0; j <= m; j++) f[0][j] = j; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1); + if (s1[i - 1] == s2[j - 1]) f[i][j] = min(f[i][j], f[i - 1][j - 1]); + } + } + return f[n][m]; + } +}; +``` +Python 代码: +```Python +class Solution: + def minDistance(self, s1: str, s2: str) -> int: + n, m = len(s1), len(s2) + f = [[0]* (m + 1) for _ in range(n + 1)] + for i in range(n + 1): + f[i][0] = i + for i in range(m + 1): + f[0][i] = i + for i in range(1, n + 1): + for j in range(1, m + 1): + f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1) + if s1[i - 1] == s2[j - 1]: + f[i][j] = min(f[i][j], f[i - 1][j - 1]) + return f[n][m] +``` +TypeScript 代码: +```TypeScript +function minDistance(s1: string, s2: string): number { + const n = s1.length, m = s2.length; + const f: number[][] = Array.from({length: n + 1}, () => Array(m + 1).fill(0)); + for(let i = 0; i <= n; i++) f[i][0] = i; + for(let i = 0; i <= m; i++) f[0][i] = i; + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= m; j++) { + f[i][j] = Math.min(f[i - 1][j] + 1, f[i][j - 1] + 1); + if (s1.charAt(i - 1) == s2.charAt(j - 1)) f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]); + } + } + return f[n][m]; +}; +``` * 时间复杂度:$O(n \times m)$ * 空间复杂度:$O(n \times m)$ diff --git "a/LeetCode/621-630/621. \344\273\273\345\212\241\350\260\203\345\272\246\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/621-630/621. \344\273\273\345\212\241\350\260\203\345\272\246\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" index b31fe854..78ca8588 100644 --- "a/LeetCode/621-630/621. \344\273\273\345\212\241\350\260\203\345\272\246\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/621-630/621. \344\273\273\345\212\241\350\260\203\345\272\246\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,11 +6,15 @@ Tag : 「构造」、「脑筋急转弯」 -给你一个用字符数组 `tasks` 表示的 `CPU` 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 `1` 个单位时间内执行完。在任何一个单位时间,`CPU` 可以完成一个任务,或者处于待命状态。 +给你一个用字符数组 `tasks` 表示的 `CPU` 需要执行的任务列表,其中每个字母表示一种不同种类的任务。 -然而,两个 相同种类 的任务之间必须有长度为整数 `n` 的冷却时间,因此至少有连续 `n` 个单位时间内 `CPU` 在执行不同的任务,或者在待命状态。 +任务可以以任意顺序执行,并且每个任务都可以在 `1` 个单位时间内执行完。 -你需要计算完成所有任务所需要的 最短时间 。 +在任何一个单位时间,`CPU` 可以完成一个任务,或者处于待命状态。 + +然而,两个相同种类的任务之间必须有长度为整数 `n` 的冷却时间,因此至少有连续 `n` 个单位时间内 `CPU` 在执行不同的任务,或者在待命状态。 + +你需要计算完成所有任务所需要的最短时间。 示例 1: ``` @@ -55,7 +59,7 @@ Tag : 「构造」、「脑筋急转弯」 先考虑最为简单的情况:假设只有一类任务,除了最后一个任务以外,其余任务在安排后均需要增加 $n$ 个单位的冻结时间。 -![image.png](https://pic.leetcode.cn/1666687680-aCVvro-image.png) +![](https://pic.leetcode.cn/1666687680-aCVvro-image.png) 将任务数记为 $m$ 个,其中前 $m - 1$ 个任务均要消耗 $n + 1$ 的单位时间,最后一个任务仅消耗 $1$ 个单位时间,即所需要的时间为 $(n + 1) \times (m - 1) + 1$。 @@ -65,7 +69,7 @@ Tag : 「构造」、「脑筋急转弯」 实际上,当任务总数不超过 $(n + 1) \times (\max - 1) + tot$ 时,我们总能将其他任务插到空闲时间中去,不会引入额外的冻结时间(下左图);而当任务数超过该值时,我们可以在将其横向添加每个 $n + 1$ 块的后面,同时不会引入额外的冻结时间(下右图): -![image.png](https://pic.leetcode.cn/1666689295-VuBpQL-image.png) +![](https://pic.leetcode.cn/1666689295-VuBpQL-image.png) 综上,我们所需要的最小时间为上述两种情况中的较大值即可: @@ -86,16 +90,18 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function leastInterval(tasks: string[], n: number): number { - const cnts = new Array(26).fill(0) - for (const c of tasks) cnts[c.charCodeAt(0) - 'A'.charCodeAt(0)]++ - let max = 0, tot = 0 - for (let i = 0; i < 26; i++) max = Math.max(max, cnts[i]) - for (let i = 0; i < 26; i++) tot += max == cnts[i] ? 1 : 0 - return Math.max(tasks.length, (n + 1) * (max - 1) + tot) -} +C++ 代码: +```C++ +class Solution { +public: + int leastInterval(vector& tasks, int n) { + vector cnts(26, 0); + for (char c : tasks) cnts[c - 'A']++; + int maxv = *max_element(cnts.begin(), cnts.end()); + int tot = count(cnts.begin(), cnts.end(), maxv); + return max(static_cast(tasks.size()), (n + 1) * (maxv - 1) + tot); + } +}; ``` Python 代码: ```Python @@ -111,6 +117,17 @@ class Solution: tot += 1 if maxv == cnts[i] else 0 return max(len(tasks), (n + 1) * (maxv - 1) + tot) ``` +TypeScript 代码: +```TypeScript +function leastInterval(tasks: string[], n: number): number { + const cnts = new Array(26).fill(0) + for (const c of tasks) cnts[c.charCodeAt(0) - 'A'.charCodeAt(0)]++ + let max = 0, tot = 0 + for (let i = 0; i < 26; i++) max = Math.max(max, cnts[i]) + for (let i = 0; i < 26; i++) tot += max == cnts[i] ? 1 : 0 + return Math.max(tasks.length, (n + 1) * (max - 1) + tot) +} +``` * 时间复杂度:$O(n + C)$ * 空间复杂度:$O(C)$,其中 $C = 26$ 为任务字符集大小 diff --git "a/LeetCode/641-650/649. Dota2 \345\217\202\350\256\256\351\231\242\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/641-650/649. Dota2 \345\217\202\350\256\256\351\231\242\357\274\210\344\270\255\347\255\211\357\274\211.md" index 9898133b..8d9f4ffb 100644 --- "a/LeetCode/641-650/649. Dota2 \345\217\202\350\256\256\351\231\242\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/641-650/649. Dota2 \345\217\202\350\256\256\351\231\242\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,22 +6,28 @@ Tag : 「贪心」、「红黑树」、「有序集合」、「队列」 -Dota2 的世界里有两个阵营:`Radiant`(天辉)和 `Dire`(夜魇) +Dota2 的世界里有两个阵营:`Radiant`(天辉)和 `Dire`(夜魇)。 -Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的 一 项: +Dota2 参议院由来自两派的参议员组成,现在参议院希望对一个 Dota2 游戏里的改变作出决定,他们以一个基于轮为过程的投票进行。 + +在每一轮中,每一位参议员都可以行使两项权利中的一项: * 禁止一名参议员的权利:参议员可以让另一位参议员在这一轮和随后的几轮中丧失所有的权利 。 -* 宣布胜利:如果参议员发现有权利投票的参议员都是 同一个阵营的 ,他可以宣布胜利并决定在游戏中的有关变化。 +* 宣布胜利:如果参议员发现有权利投票的参议员都是同一个阵营的,他可以宣布胜利并决定在游戏中的有关变化。 + +给你一个字符串 `s` 代表每个参议员的阵营。字母 `'R'` 和 `'D'`分别代表了 `Radiant`(天辉)和 `Dire`(夜魇)。 + +然后,如果有 `n` 个参议员,给定字符串的大小将是 `n`。 -给你一个字符串 `senate` 代表每个参议员的阵营。字母 `'R'` 和 `'D'`分别代表了 `Radiant`(天辉)和 `Dire`(夜魇)。然后,如果有 `n` 个参议员,给定字符串的大小将是 `n`。 +以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束,这一过程将持续到投票结束,所有失去权利的参议员将在过程中被跳过。 -以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。 +假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。 -假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 `"Radiant"` 或 `"Dire"`。 +输出应该是 `"Radiant"` 或 `"Dire"`。 示例 1: ``` -输入:senate = "RD" +输入:s = "RD" 输出:"Radiant" @@ -32,7 +38,7 @@ Dota2 参议院由来自两派的参议员组成。现在参议院希望对一 ``` 示例 2: ``` -输入:senate = "RDD" +输入:s = "RDD" 输出:"Dire" @@ -44,7 +50,7 @@ Dota2 参议院由来自两派的参议员组成。现在参议院希望对一 ``` 提示: -* $n = senate.length$ +* $n = s.length$ * $1 <= n <= 10^4$ * `senate[i]` 为 `'R'` 或 `'D'` @@ -68,7 +74,7 @@ Dota2 参议院由来自两派的参议员组成。现在参议院希望对一 当轮到 `s[idx]` 行权时(若 `s[idx]` 已被消除,则跳过本轮),从对方的有序队列中取出 **首个大于等于 `idx` 的下标**(取出代表移除);若对方的有序序列不存在该下标,而行权过程又是循环进行的,说明此时下一个行权的对方成员是 **首个大于等于 $0$** 的下标,我们对其进行取出消除,随后往后继续决策。 -Java 代码(有序集合): +Java 代码: ```Java class Solution { public String predictPartyVictory(String s) { @@ -100,12 +106,16 @@ class Solution { 因为我们在每一轮的消除中,从 `idx` 位置找到下一个决策者,总是需要遍历那些已被消除的位置,而该无效遍历操作可使用「循环队列」优化。 +--- + +### 优化 + 使用循环队列 `rd` 和 `dd` 来取代有序集合 `rs` 和 `ds`。起始将各个成员分类依次入队,每次从两队列队头中取出成员,假设从 `rs` 中取出成员下标为 `a`,从 `dd` 中取出成员下标为 `b`,对两者进行比较: * 若有 `a < b`,说明 `a` 先行权,且其消除对象为 `b`,`a` 行权后需等到下一轮,对其进行大小为 $n$ 的偏移后重新添加到 `rd` 尾部(含义为本次行权后需要等到下一轮); * 若有 `b < a`,同理,将 `a` 消除后,对 `b` 进行大小为 $n$ 的偏移后重新添加到 `dd` 尾部。 -Java 代码(循环队列): +Java 代码: ```Java class Solution { public String predictPartyVictory(String s) { @@ -124,6 +134,66 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + string predictPartyVictory(string s) { + deque rd, dd; + int n = s.length(); + for (int i = 0; i < n; i++) { + if (s[i] == 'R') rd.push_back(i); + else dd.push_back(i); + } + while (!rd.empty() && !dd.empty()) { + int a = rd.front(), b = dd.front(); + rd.pop_front(); + dd.pop_front(); + if (a < b) rd.push_back(a + n); + else dd.push_back(b + n); + } + return !rd.empty() ? "Radiant" : "Dire"; + } +}; +``` +Python 代码: +```Python +from collections import deque + +class Solution: + def predictPartyVictory(self, s: str) -> str: + rd, dd = deque(), deque() + n = len(s) + for i in range(n): + if s[i] == 'R': + rd.append(i) + else: + dd.append(i) + while rd and dd: + a, b = rd.popleft(), dd.popleft() + if a < b: + rd.append(a + n) + else: + dd.append(b + n) + return "Radiant" if rd else "Dire" +``` +TypeScript 代码: +```TypeScript +function predictPartyVictory(s: string): string { + let rd: Array = [], dd: Array = []; + let n: number = s.length; + for (let i = 0; i < n; i++) { + if (s.charAt(i) == 'R') rd.push(i); + else dd.push(i); + } + while (rd.length != 0 && dd.length != 0) { + let a: number = rd.shift()!, b: number = dd.shift()!; + if (a < b) rd.push(a + n); + else dd.push(b + n); + } + return rd.length != 0 ? "Radiant" : "Dire"; +}; +``` * 时间复杂度:将所有成员进行分队,复杂度为 $O(n)$;每个回合会有一名成员被消除,最多有 $n$ 个成员,复杂度为 $O(n)$。整体复杂度为 $O(n)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/791-800/792. \345\214\271\351\205\215\345\255\220\345\272\217\345\210\227\347\232\204\345\215\225\350\257\215\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/791-800/792. \345\214\271\351\205\215\345\255\220\345\272\217\345\210\227\347\232\204\345\215\225\350\257\215\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" index 5595184a..b6c532bd 100644 --- "a/LeetCode/791-800/792. \345\214\271\351\205\215\345\255\220\345\272\217\345\210\227\347\232\204\345\215\225\350\257\215\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/791-800/792. \345\214\271\351\205\215\345\255\220\345\272\217\345\210\227\347\232\204\345\215\225\350\257\215\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -8,7 +8,7 @@ Tag : 「二分」、「哈希表」 给定字符串 `s` 和字符串数组 `words`, 返回  `words[i]` 中是 `s` 的子序列的单词个数 。 -字符串的 子序列 是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是`""`),而不改变其余字符的相对顺序。 +字符串的子序列是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是`""`),而不改变其余字符的相对顺序。 例如, `“ace”` 是 `“abcde”` 的子序列。 @@ -119,7 +119,7 @@ function numMatchingSubseq(s: string, words: string[]): number { } ``` Python3 代码: -```Python3 +```Python class Solution: def numMatchingSubseq(self, s: str, words: List[str]) -> int: dmap = defaultdict(list) diff --git "a/LeetCode/801-810/809. \346\203\205\346\204\237\344\270\260\345\257\214\347\232\204\346\226\207\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/801-810/809. \346\203\205\346\204\237\344\270\260\345\257\214\347\232\204\346\226\207\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" index a5d89963..d1d5fd3d 100644 --- "a/LeetCode/801-810/809. \346\203\205\346\204\237\344\270\260\345\257\214\347\232\204\346\226\207\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/801-810/809. \346\203\205\346\204\237\344\270\260\345\257\214\347\232\204\346\226\207\345\255\227\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -8,9 +8,15 @@ Tag : 「双指针」、「模拟」 有时候人们会用重复写一些字母来表示额外的感受,比如 `"hello" -> "heeellooo", "hi" -> "hiii"`。我们将相邻字母都相同的一串字符定义为相同字母组,例如:`"h", "eee", "ll", "ooo"`。 -对于一个给定的字符串 `S` ,如果另一个单词能够通过将一些字母组扩张从而使其和 `S` 相同,我们将这个单词定义为可扩张的(`stretchy`)。扩张操作定义如下:选择一个字母组(包含字母 `c` ),然后往其中添加相同的字母 `c` 使其长度达到 `3` 或以上。 +对于一个给定的字符串 `S` ,如果另一个单词能够通过将一些字母组扩张从而使其和 `S` 相同,我们将这个单词定义为可扩张的(`stretchy`)。 -例如,以 `"hello"` 为例,我们可以对字母组 `"o"` 扩张得到 `"hellooo"`,但是无法以同样的方法得到 `"helloo"` 因为字母组 `"oo"` 长度小于 `3`。此外,我们可以进行另一种扩张 `"ll" -> "lllll"` 以获得 `"helllllooo"`。如果 `S = "helllllooo"`,那么查询词 `"hello"` 是可扩张的,因为可以对它执行这两种扩张操作使得 `query = "hello" -> "hellooo" -> "helllllooo" = S`。 +扩张操作定义如下:选择一个字母组(包含字母 `c` ),然后往其中添加相同的字母 `c` 使其长度达到 `3` 或以上。 + +例如,以 `"hello"` 为例: + +我们可以对字母组 `"o"` 扩张得到 `"hellooo"`,但是无法以同样的方法得到 `"helloo"` 因为字母组 `"oo"` 长度小于 `3`。此外,我们可以进行另一种扩张 `"ll" -> "lllll"` 以获得 `"helllllooo"`。 + +如果 `S = "helllllooo"`,那么查询词 `"hello"` 是可扩张的,因为可以对它执行这两种扩张操作使得 `query = "hello" -> "hellooo" -> "helllllooo" = S`。 输入一组查询单词,输出其中可扩张的单词数量。 @@ -70,25 +76,28 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function expressiveWords(s: string, words: string[]): number { - let n = s.length, ans = 0 - out:for (const word of words) { - let m = word.length, i = 0, j = 0 - while (i < n && j < m) { - if (s[i] != word[j]) continue out - let a = i, b = j - while (a < n && s[a] == s[i]) a++ - while (b < m && word[b] == word[j]) b++ - a -= i; b -= j; - if (a != b && (b > a || a < 3)) continue out - i += a; j += b; +C++ 代码: +```C++ +class Solution { +public: + int expressiveWords(string s, vector& words) { + int n = s.size(), ans = 0; + for (const string &word : words) { + int m = word.size(), i = 0, j = 0; + while (i < n && j < m) { + if (s[i] != word[j]) break; + int a = i, b = j; + while (a < n && s[a] == s[i]) a++; + while (b < m && word[b] == word[j]) b++; + a -= i; b -= j; + if (a != b && (b > a || a < 3)) break; + i += a; j += b; + if (i == n && j == m) ans++; + } } - if (i == n && j == m) ans++; + return ans; } - return ans -} +}; ``` Python 代码: ```Python @@ -114,6 +123,26 @@ class Solution: ans += 1 return ans ``` +TypeScript 代码: +```TypeScript +function expressiveWords(s: string, words: string[]): number { + let n = s.length, ans = 0 + out:for (const word of words) { + let m = word.length, i = 0, j = 0 + while (i < n && j < m) { + if (s[i] != word[j]) continue out + let a = i, b = j + while (a < n && s[a] == s[i]) a++ + while (b < m && word[b] == word[j]) b++ + a -= i; b -= j; + if (a != b && (b > a || a < 3)) continue out + i += a; j += b; + } + if (i == n && j == m) ans++; + } + return ans +} +``` * 时间复杂度:$O(n \times m + \sum_{i = 0}^{m - 1}words[i].length)$,其中 `n` 为字符串 `s` 的长度,`m` 为数组 `words` 的长度 * 空间复杂度:$O(1)$ diff --git "a/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" index f939747d..8a4001a8 100644 --- "a/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -96,36 +96,40 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function ambiguousCoordinates(_s: string): string[] { - function search(s: string, start: number, end: number): string[] { - const ans = new Array() - if (start == end || s[start] != '0') ans.push(s.substring(start, end + 1)) - for (let i = start; i < end; i++) { - const a = s.substring(start, i + 1), b = s.substring(i + 1, end + 1) - if (a.length > 1 && a[0] == '0') continue - if (b[b.length - 1] == '0') continue - ans.push(a + '.' + b) +C++ 代码: +```C++ +class Solution { +public: + string s; + vector ambiguousCoordinates(string _s) { + s = _s.substr(1, _s.size() - 2); + int n = s.size(); + vector ans; + for (int i = 0; i < n - 1; i++) { + vector a = search(0, i), b = search(i + 1, n - 1); + for (auto &x : a) { + for (auto &y : b) { + ans.push_back("(" + x + ", " + y + ")"); + } + } } - return ans + return ans; } - const s = _s.substring(1, _s.length - 1) - const n = s.length - const ans = new Array() - for (let i = 0; i < n - 1; i++) { - const a = search(s, 0, i), b = search(s, i + 1, n - 1) - for (const x of a) { - for (const y of b) { - ans.push('(' + x + ', ' + y + ')') - } + vector search(int start, int end) { + vector ans; + if (start == end || s[start] != '0') ans.push_back(s.substr(start, end - start + 1)); + for (int i = start; i < end; i++) { + string a = s.substr(start, i - start + 1), b = s.substr(i + 1, end - i); + if (a.size() > 1 && a[0] == '0') continue; + if (b.back() == '0') continue; + ans.push_back(a + "." + b); } + return ans; } - return ans -} +}; ``` Python 代码: -```Python3 +```Python class Solution: def ambiguousCoordinates(self, _s: str) -> List[str]: def search(s, start, end): @@ -150,6 +154,34 @@ class Solution: ans.append(f'({x}, {y})') return ans ``` +TypeScript 代码: +```TypeScript +function ambiguousCoordinates(_s: string): string[] { + function search(s: string, start: number, end: number): string[] { + const ans = new Array() + if (start == end || s[start] != '0') ans.push(s.substring(start, end + 1)) + for (let i = start; i < end; i++) { + const a = s.substring(start, i + 1), b = s.substring(i + 1, end + 1) + if (a.length > 1 && a[0] == '0') continue + if (b[b.length - 1] == '0') continue + ans.push(a + '.' + b) + } + return ans + } + const s = _s.substring(1, _s.length - 1) + const n = s.length + const ans = new Array() + for (let i = 0; i < n - 1; i++) { + const a = search(s, 0, i), b = search(s, i + 1, n - 1) + for (const x of a) { + for (const y of b) { + ans.push('(' + x + ', ' + y + ')') + } + } + } + return ans +} +``` * 时间复杂度:$O(n^3)$ * 空间复杂度:$O(n^3)$ diff --git "a/LeetCode/91-100/99. \346\201\242\345\244\215\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/91-100/99. \346\201\242\345\244\215\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" index f1c3f447..606a6785 100644 --- "a/LeetCode/91-100/99. \346\201\242\345\244\215\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/91-100/99. \346\201\242\345\244\215\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,10 +6,13 @@ Tag : 「二叉树」、「树的搜索」、「递归」、「迭代」、「 -给你二叉搜索树的根节点 `root`,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。 +给你二叉搜索树的根节点 `root`,该树中的 恰好 两个节点的值被错误地交换。 + +请在不改变其结构的情况下,恢复这棵树 。 示例 1: ![](https://assets.leetcode.com/uploads/2020/10/28/recover1.jpg) + ``` 输入:root = [1,3,null,null,2] @@ -136,7 +139,7 @@ Morris 遍历也就是经常说到的“神级遍历”,其本质是通过做 举个 🌰,对于一棵最简单的二叉树: -![image-20230907221810420](https://pic.leetcode.cn/1694099818-Lczfnl-image.png) +![](https://pic.leetcode.cn/1694099818-Lczfnl-image.png) 在中序遍历过程中,如果选择递归或迭代方式,并且不使用栈的情况,当遍历完左子节点(或左子树的最后一个节点)后,将会面临无法返回根节点的问题。 @@ -196,6 +199,47 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + void recoverTree(TreeNode* root) { + TreeNode *a = nullptr, *b = nullptr, *last = nullptr; + while (root != nullptr) { + if (root->left == nullptr) { + if (last != nullptr && last->val > root->val) { + if (a == nullptr) { + a = last; b = root; + } else { + b = root; + } + } + last = root; + root = root->right; + } else { + TreeNode *t = root->left; + while (t->right != nullptr && t->right != root) t = t->right; + if (t->right == nullptr) { + t->right = root; + root = root->left; + } else { + t->right = nullptr; + if (last != nullptr && last->val > root->val) { + if (a == nullptr) { + a = last, b = root; + } else { + b = root; + } + } + last = root; + root = root->right; + } + } + } + swap(a->val, b->val); + } +}; +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(1)$ diff --git "a/LeetCode/911-920/915. \345\210\206\345\211\262\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/911-920/915. \345\210\206\345\211\262\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" index 04050e55..e72386b1 100644 --- "a/LeetCode/911-920/915. \345\210\206\345\211\262\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/911-920/915. \345\210\206\345\211\262\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -12,7 +12,7 @@ Tag : 「模拟」 * `left` 和 `right` 都是非空的。 * `left` 的长度要尽可能小。 -在完成这样的分组后返回 `left` 的 长度 。 +在完成这样的分组后返回 `left` 的长度。 用例可以保证存在这样的划分方法。 @@ -62,18 +62,23 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -function partitionDisjoint(nums: number[]): number { - const n = nums.length - const min = new Array(n + 10).fill(nums[n - 1]) - for (let i = n - 2; i >= 0; i--) min[i] = Math.min(min[i + 1], nums[i]) - for (let i = 0, max = 0; i < n; i++) { - max = Math.max(max, nums[i]) - if (max <= min[i + 1]) return i + 1 +C++ 代码: +```C++ +class Solution { +public: + int partitionDisjoint(vector& nums) { + int n = nums.size(); + vector arr(n + 10); + arr[n - 1] = nums[n - 1]; + for (int i = n - 2; i >= 0; i--) arr[i] = min(arr[i + 1], nums[i]); + int maxv = 0; + for (int i = 0; i < n - 1; i++) { + maxv = max(maxv, nums[i]); + if (maxv <= arr[i + 1]) return i + 1; + } + return -1; // never } - return -1 -} +}; ``` Python 代码: ```Python @@ -91,6 +96,19 @@ class Solution: return i + 1 return -1 ``` +TypeScript 代码: +```TypeScript +function partitionDisjoint(nums: number[]): number { + const n = nums.length + const min = new Array(n + 10).fill(nums[n - 1]) + for (let i = n - 2; i >= 0; i--) min[i] = Math.min(min[i + 1], nums[i]) + for (let i = 0, max = 0; i < n; i++) { + max = Math.max(max, nums[i]) + if (max <= min[i + 1]) return i + 1 + } + return -1 +} +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/931-940/934. \346\234\200\347\237\255\347\232\204\346\241\245\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/931-940/934. \346\234\200\347\237\255\347\232\204\346\241\245\357\274\210\344\270\255\347\255\211\357\274\211.md" index c92ba66c..8ec84c68 100644 --- "a/LeetCode/931-940/934. \346\234\200\347\237\255\347\232\204\346\241\245\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/931-940/934. \346\234\200\347\237\255\347\232\204\346\241\245\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,38 +6,38 @@ Tag : 「并查集」、「双向 BFS」 -给你一个大小为 `n x n` 的二元矩阵 `grid`,其中 `1` 表示陆地,`0` 表示水域。 +给你一个大小为 `n x n` 的二元矩阵 `g`,其中 `1` 表示陆地,`0` 表示水域。 -岛 是由四面相连的 `1` 形成的一个最大组,即不会与非组内的任何其他 `1` 相连。`grid` 中 恰好存在两座岛 。 +岛是由四面相连的 `1` 形成的一个最大组,即不会与非组内的任何其他 `1` 相连,`g` 中恰好存在两座岛。 -你可以将任意数量的 `0` 变为 `1` ,以使两座岛连接起来,变成 一座岛 。 +你可以将任意数量的 `0` 变为 `1` ,以使两座岛连接起来,变成一座岛。 返回必须翻转的 `0` 的最小数目。 示例 1: ``` -输入:grid = [[0,1],[1,0]] +输入:g = [[0,1],[1,0]] 输出:1 ``` 示例 2: ``` -输入:grid = [[0,1,0],[0,0,0],[0,0,1]] +输入:g = [[0,1,0],[0,0,0],[0,0,1]] 输出:2 ``` 示例 3: ``` -输入:grid = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]] +输入:g = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]] 输出:1 ``` 提示: -* $n = grid.length = grid[i].length$ +* $n = g.length = g[i].length$ * $2 <= n <= 100$ -* `grid[i][j]` 为 `0` 或 `1` -* `grid` 中恰有两个岛 +* `g[i][j]` 为 `0` 或 `1` +* `g` 中恰有两个岛 --- @@ -45,8 +45,6 @@ Tag : 「并查集」、「双向 BFS」 **使用「并查集」将两个岛标记出来,然后将两个岛的点分别入队,再运用「双向 BFS」来找最短通路。** -为了方便,我们将 `grid` 记为 `g`。 - 对于所有满足 $g[i][j] = 1$ 的节点与其四联通的方向,值同为 $1$ 的节点进行并查集连通性维护。 随后建立两个队列 `d1` 和 `d2` 分别存储两个岛的节点(以二元组 $(x, y)$ 的方式出入队),并使用两个哈希表 `m1` 和 `m2` 来记录从两岛屿出发到达该节点所消耗的步数(以节点的一维编号为 `key`,以消耗步数为 `value`)。 @@ -128,78 +126,6 @@ class Solution { } } ``` -TypeScript 代码: -```TypeScript -let n: number -const p = new Array(10010).fill(0) -const dirs = [[0,1],[0,-1],[1,0],[-1,0]] -function shortestBridge(g: number[][]): number { - function getIdx(x: number, y: number): number { - return x * n + y - } - function find(x: number): number { - if (p[x] != x) p[x] = find(p[x]) - return p[x] - } - function union(x: number, y: number): void { - p[find(x)] = p[find(y)] - } - function update(d: Array>, m1: Map, m2: Map): number { - let sz = d.length - while (sz-- > 0) { - const info = d.shift() - const x = info[0], y = info[1], idx = getIdx(x, y), step = m1.get(idx) - for (const di of dirs) { - const nx = x + di[0], ny = y + di[1], nidx = getIdx(nx, ny) - if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue - if (m1.has(nidx)) continue - if (m2.has(nidx)) return step + 1 + m2.get(nidx) - d.push([nx, ny]) - m1.set(nidx, step + 1) - } - } - return -1 - } - n = g.length - for (let i = 0; i < n * n; i++) p[i] = i - for (let i = 0; i < n; i++) { - for (let j = 0; j < n; j++) { - if (g[i][j] == 0) continue - for (const di of dirs) { - const x = i + di[0], y = j + di[1] - if (x < 0 || x >= n || y < 0 || y >= n) continue - if (g[x][y] == 0) continue - union(getIdx(i, j), getIdx(x, y)) - } - } - } - let a = -1, b = -1 - const d1 = new Array(), d2 = new Array() - const m1 = new Map(), m2 = new Map() - for (let i = 0; i < n; i++) { - for (let j = 0; j < n; j++) { - if (g[i][j] == 0) continue - const idx = getIdx(i, j), root = find(idx) - if (a == -1) a = root - else if (a != root && b == -1) b = root - if (a == root) { - d1.push([i, j]) - m1.set(idx, 0) - } else if (b == root) { - d2.push([i, j]) - m2.set(idx, 0) - } - } - } - while (d1.length != 0 && d2.length != 0) { - let t = -1 - if (d1.length < d2.length) t = update(d1, m1, m2) - else t = update(d2, m2, m1) - if (t != -1) return t - 1 - } - return -1 -} -``` Python 代码: ```Python import queue @@ -278,6 +204,78 @@ class Solution: return t - 1 return -1 ``` +TypeScript 代码: +```TypeScript +let n: number +const p = new Array(10010).fill(0) +const dirs = [[0,1],[0,-1],[1,0],[-1,0]] +function shortestBridge(g: number[][]): number { + function getIdx(x: number, y: number): number { + return x * n + y + } + function find(x: number): number { + if (p[x] != x) p[x] = find(p[x]) + return p[x] + } + function union(x: number, y: number): void { + p[find(x)] = p[find(y)] + } + function update(d: Array>, m1: Map, m2: Map): number { + let sz = d.length + while (sz-- > 0) { + const info = d.shift() + const x = info[0], y = info[1], idx = getIdx(x, y), step = m1.get(idx) + for (const di of dirs) { + const nx = x + di[0], ny = y + di[1], nidx = getIdx(nx, ny) + if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue + if (m1.has(nidx)) continue + if (m2.has(nidx)) return step + 1 + m2.get(nidx) + d.push([nx, ny]) + m1.set(nidx, step + 1) + } + } + return -1 + } + n = g.length + for (let i = 0; i < n * n; i++) p[i] = i + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (g[i][j] == 0) continue + for (const di of dirs) { + const x = i + di[0], y = j + di[1] + if (x < 0 || x >= n || y < 0 || y >= n) continue + if (g[x][y] == 0) continue + union(getIdx(i, j), getIdx(x, y)) + } + } + } + let a = -1, b = -1 + const d1 = new Array(), d2 = new Array() + const m1 = new Map(), m2 = new Map() + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (g[i][j] == 0) continue + const idx = getIdx(i, j), root = find(idx) + if (a == -1) a = root + else if (a != root && b == -1) b = root + if (a == root) { + d1.push([i, j]) + m1.set(idx, 0) + } else if (b == root) { + d2.push([i, j]) + m2.set(idx, 0) + } + } + } + while (d1.length != 0 && d2.length != 0) { + let t = -1 + if (d1.length < d2.length) t = update(d1, m1, m2) + else t = update(d2, m2, m1) + if (t != -1) return t - 1 + } + return -1 +} +``` * 时间复杂度:$O(n^2)$ * 空间复杂度:$O(n^2)$