diff --git a/solution/1000-1099/1036.Escape a Large Maze/README.md b/solution/1000-1099/1036.Escape a Large Maze/README.md index b741ac6a3723c..c607db883ad99 100644 --- a/solution/1000-1099/1036.Escape a Large Maze/README.md +++ b/solution/1000-1099/1036.Escape a Large Maze/README.md @@ -70,7 +70,13 @@ tags: -### 方法一 +### 方法一:DFS + +题目相当于在一个 $10^6 \times 10^6$ 的网格中,给定源点和目标点,以及一小部分被封锁的点,问是否可以从源点到达目标点。 + +由于被封锁的点数量很少,最终能封锁的区域大小不超过 $|blocked|^2 / 2$,因此,我们可以从源点和目标点出发,进行深度优先搜索,直到搜索到目标点或者搜索到的点数超过 $|blocked|^2 / 2$,如果都满足,则返回 $\textit{true}$。否则返回 $\textit{false}$。 + +时间复杂度 $O(m)$,空间复杂度 $O(m)$,其中 $m$ 是被封锁的区域的大小,本题中 $m \leq |blocked|^2 / 2 = 200^2 / 2 = 20000$。 @@ -81,24 +87,21 @@ class Solution: def isEscapePossible( self, blocked: List[List[int]], source: List[int], target: List[int] ) -> bool: - def dfs(source, target, seen): - x, y = source - if ( - not (0 <= x < 10**6 and 0 <= y < 10**6) - or (x, y) in blocked - or (x, y) in seen - ): - return False - seen.add((x, y)) - if len(seen) > 20000 or source == target: + def dfs(source: List[int], target: List[int], vis: set) -> bool: + vis.add(tuple(source)) + if len(vis) > m: return True - for a, b in [[0, -1], [0, 1], [1, 0], [-1, 0]]: - next = [x + a, y + b] - if dfs(next, target, seen): - return True + for a, b in pairwise(dirs): + x, y = source[0] + a, source[1] + b + if 0 <= x < n and 0 <= y < n and (x, y) not in s and (x, y) not in vis: + if [x, y] == target or dfs([x, y], target, vis): + return True return False - blocked = set((x, y) for x, y in blocked) + s = {(x, y) for x, y in blocked} + dirs = (-1, 0, 1, 0, -1) + n = 10**6 + m = len(blocked) ** 2 // 2 return dfs(source, target, set()) and dfs(target, source, set()) ``` @@ -106,69 +109,86 @@ class Solution: ```java class Solution { - private int[][] dirs = new int[][] {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - private static final int N = (int) 1e6; - private Set blocked; + private final int n = (int) 1e6; + private int m; + private Set s = new HashSet<>(); + private final int[] dirs = {-1, 0, 1, 0, -1}; public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) { - this.blocked = new HashSet<>(); - for (int[] b : blocked) { - this.blocked.add(b[0] * N + b[1]); + for (var b : blocked) { + s.add(f(b[0], b[1])); } - return dfs(source, target, new HashSet<>()) && dfs(target, source, new HashSet<>()); - } - - private boolean dfs(int[] source, int[] target, Set seen) { + m = blocked.length * blocked.length / 2; int sx = source[0], sy = source[1]; int tx = target[0], ty = target[1]; - if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N - || blocked.contains(sx * N + sy) || seen.contains(sx * N + sy)) { - return false; - } - seen.add(sx * N + sy); - if (seen.size() > 20000 || (sx == target[0] && sy == target[1])) { + return dfs(sx, sy, tx, ty, new HashSet<>()) && dfs(tx, ty, sx, sy, new HashSet<>()); + } + + private boolean dfs(int sx, int sy, int tx, int ty, Set vis) { + if (vis.size() > m) { return true; } - for (int[] dir : dirs) { - if (dfs(new int[] {sx + dir[0], sy + dir[1]}, target, seen)) { - return true; + for (int k = 0; k < 4; ++k) { + int x = sx + dirs[k], y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x == tx && y == ty) { + return true; + } + long key = f(x, y); + if (!s.contains(key) && vis.add(key) && dfs(x, y, tx, ty, vis)) { + return true; + } } } return false; } + + private long f(int i, int j) { + return (long) i * n + j; + } } ``` #### C++ ```cpp -typedef unsigned long long ULL; - class Solution { public: - vector> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; - unordered_set blocked; - int N = 1e6; - bool isEscapePossible(vector>& blocked, vector& source, vector& target) { - this->blocked.clear(); - for (auto& b : blocked) this->blocked.insert((ULL) b[0] * N + b[1]); - unordered_set s1; - unordered_set s2; - return dfs(source, target, s1) && dfs(target, source, s2); - } - - bool dfs(vector& source, vector& target, unordered_set& seen) { + const int n = 1e6; + int m = blocked.size() * blocked.size() / 2; + using ll = long long; + unordered_set s; + const int dirs[5] = {-1, 0, 1, 0, -1}; + auto f = [&](int i, int j) { + return (ll) i * n + j; + }; + for (const auto& b : blocked) { + s.insert(f(b[0], b[1])); + } int sx = source[0], sy = source[1]; int tx = target[0], ty = target[1]; - if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || blocked.count((ULL) sx * N + sy) || seen.count((ULL) sx * N + sy)) return 0; - seen.insert((ULL) sx * N + sy); - if (seen.size() > 20000 || (sx == target[0] && sy == target[1])) return 1; - for (auto& dir : dirs) { - vector next = {sx + dir[0], sy + dir[1]}; - if (dfs(next, target, seen)) return 1; - } - return 0; + unordered_set vis1, vis2; + auto dfs = [&](this auto&& dfs, int sx, int sy, int tx, int ty, unordered_set& vis) -> bool { + vis.insert(f(sx, sy)); + if (vis.size() > m) { + return true; + } + for (int k = 0; k < 4; ++k) { + int x = sx + dirs[k], y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x == tx && y == ty) { + return true; + } + auto key = f(x, y); + if (!s.contains(key) && !vis.contains(key) && dfs(x, y, tx, ty, vis)) { + return true; + } + } + } + return false; + }; + return dfs(sx, sy, tx, ty, vis1) && dfs(tx, ty, sx, sy, vis2); } }; ``` @@ -177,84 +197,156 @@ public: ```go func isEscapePossible(blocked [][]int, source []int, target []int) bool { - const N = 1e6 - dirs := [4][2]int{{0, -1}, {0, 1}, {1, 0}, {-1, 0}} - block := make(map[int]bool) + const n = 1_000_000 + m := len(blocked) * len(blocked) / 2 + dirs := [5]int{-1, 0, 1, 0, -1} + + f := func(i, j int) int64 { + return int64(i*n + j) + } + + s := make(map[int64]bool) for _, b := range blocked { - block[b[0]*N+b[1]] = true + s[f(b[0], b[1])] = true } - var dfs func(source, target []int, seen map[int]bool) bool - dfs = func(source, target []int, seen map[int]bool) bool { - sx, sy := source[0], source[1] - tx, ty := target[0], target[1] - if sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || block[sx*N+sy] || seen[sx*N+sy] { - return false - } - seen[sx*N+sy] = true - if len(seen) > 20000 || (sx == target[0] && sy == target[1]) { + + var dfs func(sx, sy, tx, ty int, vis map[int64]bool) bool + dfs = func(sx, sy, tx, ty int, vis map[int64]bool) bool { + key := f(sx, sy) + vis[key] = true + if len(vis) > m { return true } - for _, dir := range dirs { - next := []int{sx + dir[0], sy + dir[1]} - if dfs(next, target, seen) { - return true + for k := 0; k < 4; k++ { + x, y := sx+dirs[k], sy+dirs[k+1] + if x >= 0 && x < n && y >= 0 && y < n { + if x == tx && y == ty { + return true + } + key := f(x, y) + if !s[key] && !vis[key] && dfs(x, y, tx, ty, vis) { + return true + } } } return false } - s1, s2 := make(map[int]bool), make(map[int]bool) - return dfs(source, target, s1) && dfs(target, source, s2) + + sx, sy := source[0], source[1] + tx, ty := target[0], target[1] + return dfs(sx, sy, tx, ty, map[int64]bool{}) && dfs(tx, ty, sx, sy, map[int64]bool{}) } ``` -#### Rust +#### TypeScript -```rust -use std::collections::{HashSet, VecDeque}; +```ts +function isEscapePossible(blocked: number[][], source: number[], target: number[]): boolean { + const n = 10 ** 6; + const m = (blocked.length ** 2) >> 1; + const dirs = [-1, 0, 1, 0, -1]; -const BOUNDARY: i32 = 1_000_000; -const MAX: usize = 20000; + const s = new Set(); + const f = (i: number, j: number): number => i * n + j; -impl Solution { - pub fn is_escape_possible(blocked: Vec>, source: Vec, target: Vec) -> bool { - let mut block = HashSet::with_capacity(blocked.len()); - for b in blocked.iter() { - block.insert((b[0], b[1])); - } - bfs(&block, &source, &target) && bfs(&block, &target, &source) + for (const [x, y] of blocked) { + s.add(f(x, y)); } + + const dfs = (sx: number, sy: number, tx: number, ty: number, vis: Set): boolean => { + vis.add(f(sx, sy)); + if (vis.size > m) { + return true; + } + for (let k = 0; k < 4; k++) { + const x = sx + dirs[k], + y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x === tx && y === ty) { + return true; + } + const key = f(x, y); + if (!s.has(key) && !vis.has(key) && dfs(x, y, tx, ty, vis)) { + return true; + } + } + } + return false; + }; + + return ( + dfs(source[0], source[1], target[0], target[1], new Set()) && + dfs(target[0], target[1], source[0], source[1], new Set()) + ); } +``` -fn bfs(block: &HashSet<(i32, i32)>, source: &Vec, target: &Vec) -> bool { - let dir = vec![(-1, 0), (1, 0), (0, -1), (0, 1)]; +#### Rust - let mut queue = VecDeque::new(); - let mut vis = HashSet::new(); - queue.push_back((source[0], source[1])); - vis.insert((source[0], source[1])); +```rust +use std::collections::HashSet; - while !queue.is_empty() && vis.len() < MAX { - let (x, y) = queue.pop_front().unwrap(); - if x == target[0] && y == target[1] { - return true; +impl Solution { + pub fn is_escape_possible(blocked: Vec>, source: Vec, target: Vec) -> bool { + const N: i64 = 1_000_000; + let m = (blocked.len() * blocked.len()) as i64 / 2; + + let f = |i: i64, j: i64| -> i64 { i * N + j }; + + let mut s: HashSet = HashSet::new(); + for b in &blocked { + s.insert(f(b[0] as i64, b[1] as i64)); } - for (dx, dy) in dir.iter() { - let (nx, ny) = (x + dx, y + dy); - if nx < 0 - || nx >= BOUNDARY - || ny < 0 - || ny >= BOUNDARY - || vis.contains(&(nx, ny)) - || block.contains(&(nx, ny)) - { - continue; + + fn dfs( + sx: i64, + sy: i64, + tx: i64, + ty: i64, + s: &HashSet, + m: i64, + vis: &mut HashSet, + ) -> bool { + static DIRS: [i64; 5] = [-1, 0, 1, 0, -1]; + let key = sx * 1_000_000 + sy; + vis.insert(key); + if vis.len() as i64 > m { + return true; } - queue.push_back((nx, ny)); - vis.insert((nx, ny)); + for k in 0..4 { + let x = sx + DIRS[k]; + let y = sy + DIRS[k + 1]; + let key = x * 1_000_000 + y; + if x >= 0 && x < 1_000_000 && y >= 0 && y < 1_000_000 { + if x == tx && y == ty { + return true; + } + if !s.contains(&key) && vis.insert(key) && dfs(x, y, tx, ty, s, m, vis) { + return true; + } + } + } + false } - } - vis.len() >= MAX + dfs( + source[0] as i64, + source[1] as i64, + target[0] as i64, + target[1] as i64, + &s, + m, + &mut HashSet::new(), + ) && dfs( + target[0] as i64, + target[1] as i64, + source[0] as i64, + source[1] as i64, + &s, + m, + &mut HashSet::new(), + ) + } } ``` diff --git a/solution/1000-1099/1036.Escape a Large Maze/README_EN.md b/solution/1000-1099/1036.Escape a Large Maze/README_EN.md index eaa4a95a4b6d0..5b1e38c701603 100644 --- a/solution/1000-1099/1036.Escape a Large Maze/README_EN.md +++ b/solution/1000-1099/1036.Escape a Large Maze/README_EN.md @@ -67,7 +67,13 @@ We cannot move south or west because we cannot go outside of the grid. -### Solution 1 +### Solution 1: DFS + +The problem can be interpreted as determining whether it is possible to move from a source point to a target point in a $10^6 \times 10^6$ grid, given a small number of blocked points. + +Since the number of blocked points is small, the maximum area that can be blocked is no more than $|blocked|^2 / 2$. Therefore, we can perform a depth-first search (DFS) starting from both the source and the target points. The search continues until either the target point is reached or the number of visited points exceeds $|blocked|^2 / 2$. If either condition is satisfied, return $\textit{true}$. Otherwise, return $\textit{false}$. + +Time complexity is $O(m)$, and space complexity is $O(m)$, where $m$ is the size of the blocked region. In this problem, $m \leq |blocked|^2 / 2 = 200^2 / 2 = 20000$. @@ -78,24 +84,21 @@ class Solution: def isEscapePossible( self, blocked: List[List[int]], source: List[int], target: List[int] ) -> bool: - def dfs(source, target, seen): - x, y = source - if ( - not (0 <= x < 10**6 and 0 <= y < 10**6) - or (x, y) in blocked - or (x, y) in seen - ): - return False - seen.add((x, y)) - if len(seen) > 20000 or source == target: + def dfs(source: List[int], target: List[int], vis: set) -> bool: + vis.add(tuple(source)) + if len(vis) > m: return True - for a, b in [[0, -1], [0, 1], [1, 0], [-1, 0]]: - next = [x + a, y + b] - if dfs(next, target, seen): - return True + for a, b in pairwise(dirs): + x, y = source[0] + a, source[1] + b + if 0 <= x < n and 0 <= y < n and (x, y) not in s and (x, y) not in vis: + if [x, y] == target or dfs([x, y], target, vis): + return True return False - blocked = set((x, y) for x, y in blocked) + s = {(x, y) for x, y in blocked} + dirs = (-1, 0, 1, 0, -1) + n = 10**6 + m = len(blocked) ** 2 // 2 return dfs(source, target, set()) and dfs(target, source, set()) ``` @@ -103,69 +106,86 @@ class Solution: ```java class Solution { - private int[][] dirs = new int[][] {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - private static final int N = (int) 1e6; - private Set blocked; + private final int n = (int) 1e6; + private int m; + private Set s = new HashSet<>(); + private final int[] dirs = {-1, 0, 1, 0, -1}; public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) { - this.blocked = new HashSet<>(); - for (int[] b : blocked) { - this.blocked.add(b[0] * N + b[1]); + for (var b : blocked) { + s.add(f(b[0], b[1])); } - return dfs(source, target, new HashSet<>()) && dfs(target, source, new HashSet<>()); - } - - private boolean dfs(int[] source, int[] target, Set seen) { + m = blocked.length * blocked.length / 2; int sx = source[0], sy = source[1]; int tx = target[0], ty = target[1]; - if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N - || blocked.contains(sx * N + sy) || seen.contains(sx * N + sy)) { - return false; - } - seen.add(sx * N + sy); - if (seen.size() > 20000 || (sx == target[0] && sy == target[1])) { + return dfs(sx, sy, tx, ty, new HashSet<>()) && dfs(tx, ty, sx, sy, new HashSet<>()); + } + + private boolean dfs(int sx, int sy, int tx, int ty, Set vis) { + if (vis.size() > m) { return true; } - for (int[] dir : dirs) { - if (dfs(new int[] {sx + dir[0], sy + dir[1]}, target, seen)) { - return true; + for (int k = 0; k < 4; ++k) { + int x = sx + dirs[k], y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x == tx && y == ty) { + return true; + } + long key = f(x, y); + if (!s.contains(key) && vis.add(key) && dfs(x, y, tx, ty, vis)) { + return true; + } } } return false; } + + private long f(int i, int j) { + return (long) i * n + j; + } } ``` #### C++ ```cpp -typedef unsigned long long ULL; - class Solution { public: - vector> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; - unordered_set blocked; - int N = 1e6; - bool isEscapePossible(vector>& blocked, vector& source, vector& target) { - this->blocked.clear(); - for (auto& b : blocked) this->blocked.insert((ULL) b[0] * N + b[1]); - unordered_set s1; - unordered_set s2; - return dfs(source, target, s1) && dfs(target, source, s2); - } - - bool dfs(vector& source, vector& target, unordered_set& seen) { + const int n = 1e6; + int m = blocked.size() * blocked.size() / 2; + using ll = long long; + unordered_set s; + const int dirs[5] = {-1, 0, 1, 0, -1}; + auto f = [&](int i, int j) { + return (ll) i * n + j; + }; + for (const auto& b : blocked) { + s.insert(f(b[0], b[1])); + } int sx = source[0], sy = source[1]; int tx = target[0], ty = target[1]; - if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || blocked.count((ULL) sx * N + sy) || seen.count((ULL) sx * N + sy)) return 0; - seen.insert((ULL) sx * N + sy); - if (seen.size() > 20000 || (sx == target[0] && sy == target[1])) return 1; - for (auto& dir : dirs) { - vector next = {sx + dir[0], sy + dir[1]}; - if (dfs(next, target, seen)) return 1; - } - return 0; + unordered_set vis1, vis2; + auto dfs = [&](this auto&& dfs, int sx, int sy, int tx, int ty, unordered_set& vis) -> bool { + vis.insert(f(sx, sy)); + if (vis.size() > m) { + return true; + } + for (int k = 0; k < 4; ++k) { + int x = sx + dirs[k], y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x == tx && y == ty) { + return true; + } + auto key = f(x, y); + if (!s.contains(key) && !vis.contains(key) && dfs(x, y, tx, ty, vis)) { + return true; + } + } + } + return false; + }; + return dfs(sx, sy, tx, ty, vis1) && dfs(tx, ty, sx, sy, vis2); } }; ``` @@ -174,84 +194,156 @@ public: ```go func isEscapePossible(blocked [][]int, source []int, target []int) bool { - const N = 1e6 - dirs := [4][2]int{{0, -1}, {0, 1}, {1, 0}, {-1, 0}} - block := make(map[int]bool) + const n = 1_000_000 + m := len(blocked) * len(blocked) / 2 + dirs := [5]int{-1, 0, 1, 0, -1} + + f := func(i, j int) int64 { + return int64(i*n + j) + } + + s := make(map[int64]bool) for _, b := range blocked { - block[b[0]*N+b[1]] = true + s[f(b[0], b[1])] = true } - var dfs func(source, target []int, seen map[int]bool) bool - dfs = func(source, target []int, seen map[int]bool) bool { - sx, sy := source[0], source[1] - tx, ty := target[0], target[1] - if sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || block[sx*N+sy] || seen[sx*N+sy] { - return false - } - seen[sx*N+sy] = true - if len(seen) > 20000 || (sx == target[0] && sy == target[1]) { + + var dfs func(sx, sy, tx, ty int, vis map[int64]bool) bool + dfs = func(sx, sy, tx, ty int, vis map[int64]bool) bool { + key := f(sx, sy) + vis[key] = true + if len(vis) > m { return true } - for _, dir := range dirs { - next := []int{sx + dir[0], sy + dir[1]} - if dfs(next, target, seen) { - return true + for k := 0; k < 4; k++ { + x, y := sx+dirs[k], sy+dirs[k+1] + if x >= 0 && x < n && y >= 0 && y < n { + if x == tx && y == ty { + return true + } + key := f(x, y) + if !s[key] && !vis[key] && dfs(x, y, tx, ty, vis) { + return true + } } } return false } - s1, s2 := make(map[int]bool), make(map[int]bool) - return dfs(source, target, s1) && dfs(target, source, s2) + + sx, sy := source[0], source[1] + tx, ty := target[0], target[1] + return dfs(sx, sy, tx, ty, map[int64]bool{}) && dfs(tx, ty, sx, sy, map[int64]bool{}) } ``` -#### Rust +#### TypeScript -```rust -use std::collections::{HashSet, VecDeque}; +```ts +function isEscapePossible(blocked: number[][], source: number[], target: number[]): boolean { + const n = 10 ** 6; + const m = (blocked.length ** 2) >> 1; + const dirs = [-1, 0, 1, 0, -1]; -const BOUNDARY: i32 = 1_000_000; -const MAX: usize = 20000; + const s = new Set(); + const f = (i: number, j: number): number => i * n + j; -impl Solution { - pub fn is_escape_possible(blocked: Vec>, source: Vec, target: Vec) -> bool { - let mut block = HashSet::with_capacity(blocked.len()); - for b in blocked.iter() { - block.insert((b[0], b[1])); - } - bfs(&block, &source, &target) && bfs(&block, &target, &source) + for (const [x, y] of blocked) { + s.add(f(x, y)); } + + const dfs = (sx: number, sy: number, tx: number, ty: number, vis: Set): boolean => { + vis.add(f(sx, sy)); + if (vis.size > m) { + return true; + } + for (let k = 0; k < 4; k++) { + const x = sx + dirs[k], + y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x === tx && y === ty) { + return true; + } + const key = f(x, y); + if (!s.has(key) && !vis.has(key) && dfs(x, y, tx, ty, vis)) { + return true; + } + } + } + return false; + }; + + return ( + dfs(source[0], source[1], target[0], target[1], new Set()) && + dfs(target[0], target[1], source[0], source[1], new Set()) + ); } +``` -fn bfs(block: &HashSet<(i32, i32)>, source: &Vec, target: &Vec) -> bool { - let dir = vec![(-1, 0), (1, 0), (0, -1), (0, 1)]; +#### Rust - let mut queue = VecDeque::new(); - let mut vis = HashSet::new(); - queue.push_back((source[0], source[1])); - vis.insert((source[0], source[1])); +```rust +use std::collections::HashSet; - while !queue.is_empty() && vis.len() < MAX { - let (x, y) = queue.pop_front().unwrap(); - if x == target[0] && y == target[1] { - return true; +impl Solution { + pub fn is_escape_possible(blocked: Vec>, source: Vec, target: Vec) -> bool { + const N: i64 = 1_000_000; + let m = (blocked.len() * blocked.len()) as i64 / 2; + + let f = |i: i64, j: i64| -> i64 { i * N + j }; + + let mut s: HashSet = HashSet::new(); + for b in &blocked { + s.insert(f(b[0] as i64, b[1] as i64)); } - for (dx, dy) in dir.iter() { - let (nx, ny) = (x + dx, y + dy); - if nx < 0 - || nx >= BOUNDARY - || ny < 0 - || ny >= BOUNDARY - || vis.contains(&(nx, ny)) - || block.contains(&(nx, ny)) - { - continue; + + fn dfs( + sx: i64, + sy: i64, + tx: i64, + ty: i64, + s: &HashSet, + m: i64, + vis: &mut HashSet, + ) -> bool { + static DIRS: [i64; 5] = [-1, 0, 1, 0, -1]; + let key = sx * 1_000_000 + sy; + vis.insert(key); + if vis.len() as i64 > m { + return true; } - queue.push_back((nx, ny)); - vis.insert((nx, ny)); + for k in 0..4 { + let x = sx + DIRS[k]; + let y = sy + DIRS[k + 1]; + let key = x * 1_000_000 + y; + if x >= 0 && x < 1_000_000 && y >= 0 && y < 1_000_000 { + if x == tx && y == ty { + return true; + } + if !s.contains(&key) && vis.insert(key) && dfs(x, y, tx, ty, s, m, vis) { + return true; + } + } + } + false } - } - vis.len() >= MAX + dfs( + source[0] as i64, + source[1] as i64, + target[0] as i64, + target[1] as i64, + &s, + m, + &mut HashSet::new(), + ) && dfs( + target[0] as i64, + target[1] as i64, + source[0] as i64, + source[1] as i64, + &s, + m, + &mut HashSet::new(), + ) + } } ``` diff --git a/solution/1000-1099/1036.Escape a Large Maze/Solution.cpp b/solution/1000-1099/1036.Escape a Large Maze/Solution.cpp index 06d3f36870959..68fb3902b0f11 100644 --- a/solution/1000-1099/1036.Escape a Large Maze/Solution.cpp +++ b/solution/1000-1099/1036.Escape a Large Maze/Solution.cpp @@ -1,29 +1,39 @@ -typedef unsigned long long ULL; - class Solution { public: - vector> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; - unordered_set blocked; - int N = 1e6; - bool isEscapePossible(vector>& blocked, vector& source, vector& target) { - this->blocked.clear(); - for (auto& b : blocked) this->blocked.insert((ULL) b[0] * N + b[1]); - unordered_set s1; - unordered_set s2; - return dfs(source, target, s1) && dfs(target, source, s2); - } - - bool dfs(vector& source, vector& target, unordered_set& seen) { + const int n = 1e6; + int m = blocked.size() * blocked.size() / 2; + using ll = long long; + unordered_set s; + const int dirs[5] = {-1, 0, 1, 0, -1}; + auto f = [&](int i, int j) { + return (ll) i * n + j; + }; + for (const auto& b : blocked) { + s.insert(f(b[0], b[1])); + } int sx = source[0], sy = source[1]; int tx = target[0], ty = target[1]; - if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || blocked.count((ULL) sx * N + sy) || seen.count((ULL) sx * N + sy)) return 0; - seen.insert((ULL) sx * N + sy); - if (seen.size() > 20000 || (sx == target[0] && sy == target[1])) return 1; - for (auto& dir : dirs) { - vector next = {sx + dir[0], sy + dir[1]}; - if (dfs(next, target, seen)) return 1; - } - return 0; + unordered_set vis1, vis2; + auto dfs = [&](this auto&& dfs, int sx, int sy, int tx, int ty, unordered_set& vis) -> bool { + vis.insert(f(sx, sy)); + if (vis.size() > m) { + return true; + } + for (int k = 0; k < 4; ++k) { + int x = sx + dirs[k], y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x == tx && y == ty) { + return true; + } + auto key = f(x, y); + if (!s.contains(key) && !vis.contains(key) && dfs(x, y, tx, ty, vis)) { + return true; + } + } + } + return false; + }; + return dfs(sx, sy, tx, ty, vis1) && dfs(tx, ty, sx, sy, vis2); } }; \ No newline at end of file diff --git a/solution/1000-1099/1036.Escape a Large Maze/Solution.go b/solution/1000-1099/1036.Escape a Large Maze/Solution.go index 8ca3810178393..12009d78c98b3 100644 --- a/solution/1000-1099/1036.Escape a Large Maze/Solution.go +++ b/solution/1000-1099/1036.Escape a Large Maze/Solution.go @@ -1,29 +1,40 @@ func isEscapePossible(blocked [][]int, source []int, target []int) bool { - const N = 1e6 - dirs := [4][2]int{{0, -1}, {0, 1}, {1, 0}, {-1, 0}} - block := make(map[int]bool) + const n = 1_000_000 + m := len(blocked) * len(blocked) / 2 + dirs := [5]int{-1, 0, 1, 0, -1} + + f := func(i, j int) int64 { + return int64(i*n + j) + } + + s := make(map[int64]bool) for _, b := range blocked { - block[b[0]*N+b[1]] = true + s[f(b[0], b[1])] = true } - var dfs func(source, target []int, seen map[int]bool) bool - dfs = func(source, target []int, seen map[int]bool) bool { - sx, sy := source[0], source[1] - tx, ty := target[0], target[1] - if sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || block[sx*N+sy] || seen[sx*N+sy] { - return false - } - seen[sx*N+sy] = true - if len(seen) > 20000 || (sx == target[0] && sy == target[1]) { + + var dfs func(sx, sy, tx, ty int, vis map[int64]bool) bool + dfs = func(sx, sy, tx, ty int, vis map[int64]bool) bool { + key := f(sx, sy) + vis[key] = true + if len(vis) > m { return true } - for _, dir := range dirs { - next := []int{sx + dir[0], sy + dir[1]} - if dfs(next, target, seen) { - return true + for k := 0; k < 4; k++ { + x, y := sx+dirs[k], sy+dirs[k+1] + if x >= 0 && x < n && y >= 0 && y < n { + if x == tx && y == ty { + return true + } + key := f(x, y) + if !s[key] && !vis[key] && dfs(x, y, tx, ty, vis) { + return true + } } } return false } - s1, s2 := make(map[int]bool), make(map[int]bool) - return dfs(source, target, s1) && dfs(target, source, s2) -} \ No newline at end of file + + sx, sy := source[0], source[1] + tx, ty := target[0], target[1] + return dfs(sx, sy, tx, ty, map[int64]bool{}) && dfs(tx, ty, sx, sy, map[int64]bool{}) +} diff --git a/solution/1000-1099/1036.Escape a Large Maze/Solution.java b/solution/1000-1099/1036.Escape a Large Maze/Solution.java index a5564a2f72044..13f7f46e1b551 100644 --- a/solution/1000-1099/1036.Escape a Large Maze/Solution.java +++ b/solution/1000-1099/1036.Escape a Large Maze/Solution.java @@ -1,32 +1,39 @@ class Solution { - private int[][] dirs = new int[][] {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - private static final int N = (int) 1e6; - private Set blocked; + private final int n = (int) 1e6; + private int m; + private Set s = new HashSet<>(); + private final int[] dirs = {-1, 0, 1, 0, -1}; public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) { - this.blocked = new HashSet<>(); - for (int[] b : blocked) { - this.blocked.add(b[0] * N + b[1]); + for (var b : blocked) { + s.add(f(b[0], b[1])); } - return dfs(source, target, new HashSet<>()) && dfs(target, source, new HashSet<>()); - } - - private boolean dfs(int[] source, int[] target, Set seen) { + m = blocked.length * blocked.length / 2; int sx = source[0], sy = source[1]; int tx = target[0], ty = target[1]; - if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N - || blocked.contains(sx * N + sy) || seen.contains(sx * N + sy)) { - return false; - } - seen.add(sx * N + sy); - if (seen.size() > 20000 || (sx == target[0] && sy == target[1])) { + return dfs(sx, sy, tx, ty, new HashSet<>()) && dfs(tx, ty, sx, sy, new HashSet<>()); + } + + private boolean dfs(int sx, int sy, int tx, int ty, Set vis) { + if (vis.size() > m) { return true; } - for (int[] dir : dirs) { - if (dfs(new int[] {sx + dir[0], sy + dir[1]}, target, seen)) { - return true; + for (int k = 0; k < 4; ++k) { + int x = sx + dirs[k], y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x == tx && y == ty) { + return true; + } + long key = f(x, y); + if (!s.contains(key) && vis.add(key) && dfs(x, y, tx, ty, vis)) { + return true; + } } } return false; } + + private long f(int i, int j) { + return (long) i * n + j; + } } \ No newline at end of file diff --git a/solution/1000-1099/1036.Escape a Large Maze/Solution.py b/solution/1000-1099/1036.Escape a Large Maze/Solution.py index 4d6f067cf67ee..14455b34ec195 100644 --- a/solution/1000-1099/1036.Escape a Large Maze/Solution.py +++ b/solution/1000-1099/1036.Escape a Large Maze/Solution.py @@ -2,22 +2,19 @@ class Solution: def isEscapePossible( self, blocked: List[List[int]], source: List[int], target: List[int] ) -> bool: - def dfs(source, target, seen): - x, y = source - if ( - not (0 <= x < 10**6 and 0 <= y < 10**6) - or (x, y) in blocked - or (x, y) in seen - ): - return False - seen.add((x, y)) - if len(seen) > 20000 or source == target: + def dfs(source: List[int], target: List[int], vis: set) -> bool: + vis.add(tuple(source)) + if len(vis) > m: return True - for a, b in [[0, -1], [0, 1], [1, 0], [-1, 0]]: - next = [x + a, y + b] - if dfs(next, target, seen): - return True + for a, b in pairwise(dirs): + x, y = source[0] + a, source[1] + b + if 0 <= x < n and 0 <= y < n and (x, y) not in s and (x, y) not in vis: + if [x, y] == target or dfs([x, y], target, vis): + return True return False - blocked = set((x, y) for x, y in blocked) + s = {(x, y) for x, y in blocked} + dirs = (-1, 0, 1, 0, -1) + n = 10**6 + m = len(blocked) ** 2 // 2 return dfs(source, target, set()) and dfs(target, source, set()) diff --git a/solution/1000-1099/1036.Escape a Large Maze/Solution.rs b/solution/1000-1099/1036.Escape a Large Maze/Solution.rs index 19e88060f539e..9544204153c81 100644 --- a/solution/1000-1099/1036.Escape a Large Maze/Solution.rs +++ b/solution/1000-1099/1036.Escape a Large Maze/Solution.rs @@ -1,46 +1,64 @@ -use std::collections::{HashSet, VecDeque}; - -const BOUNDARY: i32 = 1_000_000; -const MAX: usize = 20000; +use std::collections::HashSet; impl Solution { pub fn is_escape_possible(blocked: Vec>, source: Vec, target: Vec) -> bool { - let mut block = HashSet::with_capacity(blocked.len()); - for b in blocked.iter() { - block.insert((b[0], b[1])); - } - bfs(&block, &source, &target) && bfs(&block, &target, &source) - } -} - -fn bfs(block: &HashSet<(i32, i32)>, source: &Vec, target: &Vec) -> bool { - let dir = vec![(-1, 0), (1, 0), (0, -1), (0, 1)]; + const N: i64 = 1_000_000; + let m = (blocked.len() * blocked.len()) as i64 / 2; - let mut queue = VecDeque::new(); - let mut vis = HashSet::new(); - queue.push_back((source[0], source[1])); - vis.insert((source[0], source[1])); + let f = |i: i64, j: i64| -> i64 { i * N + j }; - while !queue.is_empty() && vis.len() < MAX { - let (x, y) = queue.pop_front().unwrap(); - if x == target[0] && y == target[1] { - return true; + let mut s: HashSet = HashSet::new(); + for b in &blocked { + s.insert(f(b[0] as i64, b[1] as i64)); } - for (dx, dy) in dir.iter() { - let (nx, ny) = (x + dx, y + dy); - if nx < 0 - || nx >= BOUNDARY - || ny < 0 - || ny >= BOUNDARY - || vis.contains(&(nx, ny)) - || block.contains(&(nx, ny)) - { - continue; + + fn dfs( + sx: i64, + sy: i64, + tx: i64, + ty: i64, + s: &HashSet, + m: i64, + vis: &mut HashSet, + ) -> bool { + static DIRS: [i64; 5] = [-1, 0, 1, 0, -1]; + let key = sx * 1_000_000 + sy; + vis.insert(key); + if vis.len() as i64 > m { + return true; + } + for k in 0..4 { + let x = sx + DIRS[k]; + let y = sy + DIRS[k + 1]; + let key = x * 1_000_000 + y; + if x >= 0 && x < 1_000_000 && y >= 0 && y < 1_000_000 { + if x == tx && y == ty { + return true; + } + if !s.contains(&key) && vis.insert(key) && dfs(x, y, tx, ty, s, m, vis) { + return true; + } + } } - queue.push_back((nx, ny)); - vis.insert((nx, ny)); + false } - } - vis.len() >= MAX + dfs( + source[0] as i64, + source[1] as i64, + target[0] as i64, + target[1] as i64, + &s, + m, + &mut HashSet::new(), + ) && dfs( + target[0] as i64, + target[1] as i64, + source[0] as i64, + source[1] as i64, + &s, + m, + &mut HashSet::new(), + ) + } } diff --git a/solution/1000-1099/1036.Escape a Large Maze/Solution.ts b/solution/1000-1099/1036.Escape a Large Maze/Solution.ts new file mode 100644 index 0000000000000..c86ebb5257bf7 --- /dev/null +++ b/solution/1000-1099/1036.Escape a Large Maze/Solution.ts @@ -0,0 +1,38 @@ +function isEscapePossible(blocked: number[][], source: number[], target: number[]): boolean { + const n = 10 ** 6; + const m = (blocked.length ** 2) >> 1; + const dirs = [-1, 0, 1, 0, -1]; + + const s = new Set(); + const f = (i: number, j: number): number => i * n + j; + + for (const [x, y] of blocked) { + s.add(f(x, y)); + } + + const dfs = (sx: number, sy: number, tx: number, ty: number, vis: Set): boolean => { + vis.add(f(sx, sy)); + if (vis.size > m) { + return true; + } + for (let k = 0; k < 4; k++) { + const x = sx + dirs[k], + y = sy + dirs[k + 1]; + if (x >= 0 && x < n && y >= 0 && y < n) { + if (x === tx && y === ty) { + return true; + } + const key = f(x, y); + if (!s.has(key) && !vis.has(key) && dfs(x, y, tx, ty, vis)) { + return true; + } + } + } + return false; + }; + + return ( + dfs(source[0], source[1], target[0], target[1], new Set()) && + dfs(target[0], target[1], source[0], source[1], new Set()) + ); +} diff --git a/solution/1000-1099/1037.Valid Boomerang/README_EN.md b/solution/1000-1099/1037.Valid Boomerang/README_EN.md index 37a8651157d69..5c94dd25195a6 100644 --- a/solution/1000-1099/1037.Valid Boomerang/README_EN.md +++ b/solution/1000-1099/1037.Valid Boomerang/README_EN.md @@ -47,7 +47,18 @@ tags: -### Solution 1 +### Solution 1: Slope Comparison + +Let the three points be $(x_1, y_1)$, $(x_2, y_2)$, and $(x_3, y_3)$. The formula for calculating the slope between two points is $\frac{y_2 - y_1}{x_2 - x_1}$. + +To ensure that the three points are not collinear, the condition $\frac{y_2 - y_1}{x_2 - x_1} \neq \frac{y_3 - y_2}{x_3 - x_2}$ must be satisfied. By transforming the equation, we get $(y_2 - y_1) \cdot (x_3 - x_2) \neq (y_3 - y_2) \cdot (x_2 - x_1)$. + +Note: + +1. When the slope between two points does not exist, i.e., $x_1 = x_2$, the transformed equation still holds. +2. If there are precision issues with division in slope comparison, it can be converted to multiplication. + +Time complexity is $O(1)$. diff --git a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README.md b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README.md index 51d5dd2846f39..fa007bee123f2 100644 --- a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README.md +++ b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README.md @@ -87,12 +87,12 @@ tags: # self.left = left # self.right = right class Solution: - def bstToGst(self, root: TreeNode) -> TreeNode: - def dfs(root): - nonlocal s + def bstToGst(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + def dfs(root: Optional[TreeNode]): if root is None: return dfs(root.right) + nonlocal s s += root.val root.val = s dfs(root.left) @@ -156,20 +156,20 @@ class Solution { */ class Solution { public: - int s = 0; - TreeNode* bstToGst(TreeNode* root) { + int s = 0; + auto dfs = [&](this auto&& dfs, TreeNode* root) { + if (!root) { + return; + } + dfs(root->right); + s += root->val; + root->val = s; + dfs(root->left); + }; dfs(root); return root; } - - void dfs(TreeNode* root) { - if (!root) return; - dfs(root->right); - s += root->val; - root->val = s; - dfs(root->left); - } }; ``` @@ -219,17 +219,17 @@ func bstToGst(root *TreeNode) *TreeNode { */ function bstToGst(root: TreeNode | null): TreeNode | null { - const dfs = (root: TreeNode | null, sum: number) => { - if (root == null) { - return sum; + let s = 0; + const dfs = (root: TreeNode | null) => { + if (!root) { + return; } - const { val, left, right } = root; - sum = dfs(right, sum) + val; - root.val = sum; - sum = dfs(left, sum); - return sum; + dfs(root.right); + s += root.val; + root.val = s; + dfs(root.left); }; - dfs(root, 0); + dfs(root); return root; } ``` @@ -255,22 +255,24 @@ function bstToGst(root: TreeNode | null): TreeNode | null { // } // } // } -use std::cell::RefCell; use std::rc::Rc; +use std::cell::RefCell; + impl Solution { - fn dfs(root: &mut Option>>, mut sum: i32) -> i32 { - if let Some(node) = root { - let mut node = node.as_ref().borrow_mut(); - sum = Self::dfs(&mut node.right, sum) + node.val; - node.val = sum; - sum = Self::dfs(&mut node.left, sum); - } - sum + pub fn bst_to_gst(root: Option>>) -> Option>> { + let mut s = 0; + Self::dfs(&root, &mut s); + root } - pub fn bst_to_gst(mut root: Option>>) -> Option>> { - Self::dfs(&mut root, 0); - root + fn dfs(root: &Option>>, s: &mut i32) { + if let Some(node) = root { + let mut node = node.borrow_mut(); + Self::dfs(&node.right, s); + *s += node.val; + node.val = *s; + Self::dfs(&node.left, s); + } } } ``` diff --git a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README_EN.md b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README_EN.md index f0b0a6a082837..97d3ea002dab7 100644 --- a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README_EN.md +++ b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/README_EN.md @@ -64,7 +64,11 @@ tags: -### Solution 1 +### Solution 1: Recursion + +Traverse the binary search tree in the order of "right-root-left". Accumulate all the node values encountered into $s$, and assign the accumulated value to the corresponding `node`. + +Time complexity is $O(n)$, and space complexity is $O(n)$, where $n$ is the number of nodes in the binary search tree. @@ -78,12 +82,12 @@ tags: # self.left = left # self.right = right class Solution: - def bstToGst(self, root: TreeNode) -> TreeNode: - def dfs(root): - nonlocal s + def bstToGst(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + def dfs(root: Optional[TreeNode]): if root is None: return dfs(root.right) + nonlocal s s += root.val root.val = s dfs(root.left) @@ -147,20 +151,20 @@ class Solution { */ class Solution { public: - int s = 0; - TreeNode* bstToGst(TreeNode* root) { + int s = 0; + auto dfs = [&](this auto&& dfs, TreeNode* root) { + if (!root) { + return; + } + dfs(root->right); + s += root->val; + root->val = s; + dfs(root->left); + }; dfs(root); return root; } - - void dfs(TreeNode* root) { - if (!root) return; - dfs(root->right); - s += root->val; - root->val = s; - dfs(root->left); - } }; ``` @@ -210,17 +214,17 @@ func bstToGst(root *TreeNode) *TreeNode { */ function bstToGst(root: TreeNode | null): TreeNode | null { - const dfs = (root: TreeNode | null, sum: number) => { - if (root == null) { - return sum; + let s = 0; + const dfs = (root: TreeNode | null) => { + if (!root) { + return; } - const { val, left, right } = root; - sum = dfs(right, sum) + val; - root.val = sum; - sum = dfs(left, sum); - return sum; + dfs(root.right); + s += root.val; + root.val = s; + dfs(root.left); }; - dfs(root, 0); + dfs(root); return root; } ``` @@ -246,22 +250,24 @@ function bstToGst(root: TreeNode | null): TreeNode | null { // } // } // } -use std::cell::RefCell; use std::rc::Rc; +use std::cell::RefCell; + impl Solution { - fn dfs(root: &mut Option>>, mut sum: i32) -> i32 { - if let Some(node) = root { - let mut node = node.as_ref().borrow_mut(); - sum = Self::dfs(&mut node.right, sum) + node.val; - node.val = sum; - sum = Self::dfs(&mut node.left, sum); - } - sum + pub fn bst_to_gst(root: Option>>) -> Option>> { + let mut s = 0; + Self::dfs(&root, &mut s); + root } - pub fn bst_to_gst(mut root: Option>>) -> Option>> { - Self::dfs(&mut root, 0); - root + fn dfs(root: &Option>>, s: &mut i32) { + if let Some(node) = root { + let mut node = node.borrow_mut(); + Self::dfs(&node.right, s); + *s += node.val; + node.val = *s; + Self::dfs(&node.left, s); + } } } ``` @@ -330,7 +336,20 @@ struct TreeNode* bstToGst(struct TreeNode* root) { -### Solution 2 +### Solution 2: Morris Traversal + +Morris traversal does not require a stack, with a time complexity of $O(n)$ and a space complexity of $O(1)$. The core idea is as follows: + +Define $s$ as the cumulative sum of the node values in the binary search tree. Traverse the binary tree nodes: + +1. If the right subtree of the current node `root` is null, **add the current node value to $s$**, update the current node value to $s$, and move the current node to `root.left`. +2. If the right subtree of the current node `root` is not null, find the leftmost node `next` in the right subtree (i.e., the successor node of `root` in an in-order traversal): + - If the left subtree of the successor node `next` is null, set the left subtree of `next` to point to the current node `root`, and move the current node to `root.right`. + - If the left subtree of the successor node `next` is not null, **add the current node value to $s$**, update the current node value to $s$, then set the left subtree of `next` to null (i.e., remove the link between `next` and `root`), and move the current node to `root.left`. +3. Repeat the above steps until the binary tree nodes are null, at which point the traversal is complete. +4. Finally, return the root node of the binary search tree. + +> Morris reverse in-order traversal follows the same idea as Morris in-order traversal, except that the traversal order changes from "left-root-right" to "right-root-left". diff --git a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.cpp b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.cpp index e3f8ad1c493cf..325fdd44c7aea 100644 --- a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.cpp +++ b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.cpp @@ -11,18 +11,18 @@ */ class Solution { public: - int s = 0; - TreeNode* bstToGst(TreeNode* root) { + int s = 0; + auto dfs = [&](this auto&& dfs, TreeNode* root) { + if (!root) { + return; + } + dfs(root->right); + s += root->val; + root->val = s; + dfs(root->left); + }; dfs(root); return root; } - - void dfs(TreeNode* root) { - if (!root) return; - dfs(root->right); - s += root->val; - root->val = s; - dfs(root->left); - } }; \ No newline at end of file diff --git a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.py b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.py index db01d320edb78..d03ef87bb5eee 100644 --- a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.py +++ b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.py @@ -5,12 +5,12 @@ # self.left = left # self.right = right class Solution: - def bstToGst(self, root: TreeNode) -> TreeNode: - def dfs(root): - nonlocal s + def bstToGst(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + def dfs(root: Optional[TreeNode]): if root is None: return dfs(root.right) + nonlocal s s += root.val root.val = s dfs(root.left) diff --git a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.rs b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.rs index f2b6b87562fe8..55ab171abbfbc 100644 --- a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.rs +++ b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.rs @@ -18,19 +18,21 @@ // } use std::cell::RefCell; use std::rc::Rc; + impl Solution { - fn dfs(root: &mut Option>>, mut sum: i32) -> i32 { - if let Some(node) = root { - let mut node = node.as_ref().borrow_mut(); - sum = Self::dfs(&mut node.right, sum) + node.val; - node.val = sum; - sum = Self::dfs(&mut node.left, sum); - } - sum + pub fn bst_to_gst(root: Option>>) -> Option>> { + let mut s = 0; + Self::dfs(&root, &mut s); + root } - pub fn bst_to_gst(mut root: Option>>) -> Option>> { - Self::dfs(&mut root, 0); - root + fn dfs(root: &Option>>, s: &mut i32) { + if let Some(node) = root { + let mut node = node.borrow_mut(); + Self::dfs(&node.right, s); + *s += node.val; + node.val = *s; + Self::dfs(&node.left, s); + } } } diff --git a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.ts b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.ts index 2f90397898b6c..f2346fdc247d0 100644 --- a/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.ts +++ b/solution/1000-1099/1038.Binary Search Tree to Greater Sum Tree/Solution.ts @@ -13,16 +13,16 @@ */ function bstToGst(root: TreeNode | null): TreeNode | null { - const dfs = (root: TreeNode | null, sum: number) => { - if (root == null) { - return sum; + let s = 0; + const dfs = (root: TreeNode | null) => { + if (!root) { + return; } - const { val, left, right } = root; - sum = dfs(right, sum) + val; - root.val = sum; - sum = dfs(left, sum); - return sum; + dfs(root.right); + s += root.val; + root.val = s; + dfs(root.left); }; - dfs(root, 0); + dfs(root); return root; } diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md index 9ed3d3a56d38a..be992f1578ac9 100644 --- a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md @@ -77,17 +77,17 @@ tags: ### 方法一:记忆化搜索 -我们设计一个函数 $dfs(i, j)$,表示将多边形的顶点 $i$ 到 $j$ 进行三角剖分后的最低分数。那么答案就是 $dfs(0, n - 1)$。 +我们设计一个函数 $\text{dfs}(i, j)$,表示将多边形的顶点 $i$ 到 $j$ 进行三角剖分后的最低分数。那么答案就是 $\text{dfs}(0, n - 1)$。 -函数 $dfs(i, j)$ 的计算过程如下: +函数 $\text{dfs}(i, j)$ 的计算过程如下: 如果 $i + 1 = j$,说明多边形只有两个顶点,无法进行三角剖分,返回 $0$; -否则,我们枚举 $i$ 和 $j$ 之间的一个顶点 $k$,即 $i \lt k \lt j$,将多边形的顶点 $i$ 到 $j$ 进行三角剖分,可以分为两个子问题:将多边形的顶点 $i$ 到 $k$ 进行三角剖分,以及将多边形的顶点 $k$ 到 $j$ 进行三角剖分。这两个子问题的最低分数分别为 $dfs(i, k)$ 和 $dfs(k, j)$,而顶点 $i$, $j$ 和 $k$ 构成的三角形的分数为 $values[i] \times values[k] \times values[j]$。那么,此次三角剖分的最低分数为 $dfs(i, k) + dfs(k, j) + values[i] \times values[k] \times values[j]$,我们取所有可能的最小值,即为 $dfs(i, j)$ 的值。 +否则,我们枚举 $i$ 和 $j$ 之间的一个顶点 $k$,即 $i \lt k \lt j$,将多边形的顶点 $i$ 到 $j$ 进行三角剖分,可以分为两个子问题:将多边形的顶点 $i$ 到 $k$ 进行三角剖分,以及将多边形的顶点 $k$ 到 $j$ 进行三角剖分。这两个子问题的最低分数分别为 $\text{dfs}(i, k)$ 和 $\text{dfs}(k, j)$,而顶点 $i$, $j$ 和 $k$ 构成的三角形的分数为 $\text{values}[i] \times \text{values}[k] \times \text{values}[j]$。那么,此次三角剖分的最低分数为 $\text{dfs}(i, k) + \text{dfs}(k, j) + \text{values}[i] \times \text{values}[k] \times \text{values}[j]$,我们取所有可能的最小值,即为 $\text{dfs}(i, j)$ 的值。 为了避免重复计算,我们可以使用记忆化搜索,即使用哈希表或者数组来存储已经计算过的函数值。 -最后,我们返回 $dfs(0, n - 1)$ 即可。 +最后,我们返回 $\text{dfs}(0, n - 1)$ 即可。 时间复杂度 $O(n^3)$,空间复杂度 $O(n^2)$。其中 $n$ 为多边形的顶点数。 @@ -230,7 +230,7 @@ function minScoreTriangulation(values: number[]): number { 对于 $f[i][j]$(这里要求 $i + 1 \lt j$),我们先将 $f[i][j]$ 初始化为 $\infty$。 -我们枚举 $i$ 和 $j$ 之间的一个顶点 $k$,即 $i \lt k \lt j$,将多边形的顶点 $i$ 到 $j$ 进行三角剖分,可以分为两个子问题:将多边形的顶点 $i$ 到 $k$ 进行三角剖分,以及将多边形的顶点 $k$ 到 $j$ 进行三角剖分。这两个子问题的最低分数分别为 $f[i][k]$ 和 $f[k][j]$,而顶点 $i$, $j$ 和 $k$ 构成的三角形的分数为 $values[i] \times values[k] \times values[j]$。那么,此次三角剖分的最低分数为 $f[i][k] + f[k][j] + values[i] \times values[k] \times values[j]$,我们取所有可能的最小值,即为 $f[i][j]$ 的值。 +我们枚举 $i$ 和 $j$ 之间的一个顶点 $k$,即 $i \lt k \lt j$,将多边形的顶点 $i$ 到 $j$ 进行三角剖分,可以分为两个子问题:将多边形的顶点 $i$ 到 $k$ 进行三角剖分,以及将多边形的顶点 $k$ 到 $j$ 进行三角剖分。这两个子问题的最低分数分别为 $f[i][k]$ 和 $f[k][j]$,而顶点 $i$, $j$ 和 $k$ 构成的三角形的分数为 $\text{values}[i] \times \text{values}[k] \times \text{values}[j]$。那么,此次三角剖分的最低分数为 $f[i][k] + f[k][j] + \text{values}[i] \times \text{values}[k] \times \text{values}[j]$,我们取所有可能的最小值,即为 $f[i][j]$ 的值。 综上,我们可以得到状态转移方程: @@ -238,7 +238,8 @@ $$ f[i][j]= \begin{cases} 0, & i+1=j \\ -\min_{i -### 方法三 +### 方法三:动态规划(另一种实现方式) + +方法二中,我们提到了两种枚举方式。这里我们使用第二种方式,从小到大枚举区间长度 $l$,其中 $3 \leq l \leq n$,然后枚举区间左端点 $i$,那么可以得到右端点 $j=i + l - 1$。 + +时间复杂度 $O(n^3)$,空间复杂度 $O(n^2)$。其中 $n$ 为多边形的顶点数。 diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md index dc5f2cece7f3d..cd7b0d350a1b9 100644 --- a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md @@ -80,7 +80,20 @@ The minimum score is 144.

-### Solution 1 +### Solution 1: Memoization + +We design a function $\text{dfs}(i, j)$, which represents the minimum score after triangulating the polygon from vertex $i$ to $j$. The answer is $\text{dfs}(0, n - 1)$. + +The calculation process of $\text{dfs}(i, j)$ is as follows: + +- If $i + 1 = j$, it means the polygon has only two vertices and cannot be triangulated, so we return $0$; +- Otherwise, we enumerate a vertex $k$ between $i$ and $j$, i.e., $i \lt k \lt j$. Triangulating the polygon from vertex $i$ to $j$ can be divided into two subproblems: triangulating the polygon from vertex $i$ to $k$ and triangulating the polygon from vertex $k$ to $j$. The minimum scores of these two subproblems are $\text{dfs}(i, k)$ and $\text{dfs}(k, j)$, respectively. The score of the triangle formed by vertices $i$, $j$, and $k$ is $\text{values}[i] \times \text{values}[k] \times \text{values}[j]$. Thus, the minimum score for this triangulation is $\text{dfs}(i, k) + \text{dfs}(k, j) + \text{values}[i] \times \text{values}[k] \times \text{values}[j]$. We take the minimum value of all possibilities, which is the value of $\text{dfs}(i, j)$. + +To avoid repeated calculations, we can use memoization, i.e., use a hash table or an array to store the already computed function values. + +Finally, we return $\text{dfs}(0, n - 1)$. + +The time complexity is $O(n^3)$, and the space complexity is $O(n^2)$, where $n$ is the number of vertices in the polygon. @@ -213,7 +226,39 @@ function minScoreTriangulation(values: number[]): number { -### Solution 2 +### Solution 2: Dynamic Programming + +We can convert the memoization approach in Solution 1 into a dynamic programming approach. + +Define $f[i][j]$ as the minimum score after triangulating the polygon from vertex $i$ to $j$. Initially, $f[i][j] = 0$, and the answer is $f[0][n-1]$. + +For $f[i][j]$ (where $i + 1 \lt j$), we first initialize $f[i][j]$ to $\infty$. + +We enumerate a vertex $k$ between $i$ and $j$, i.e., $i \lt k \lt j$. Triangulating the polygon from vertex $i$ to $j$ can be divided into two subproblems: triangulating the polygon from vertex $i$ to $k$ and triangulating the polygon from vertex $k$ to $j$. The minimum scores of these two subproblems are $f[i][k]$ and $f[k][j]$, respectively. The score of the triangle formed by vertices $i$, $j$, and $k$ is $\text{values}[i] \times \text{values}[k] \times \text{values}[j]$. Thus, the minimum score for this triangulation is $f[i][k] + f[k][j] + \text{values}[i] \times \text{values}[k] \times \text{values}[j]$. We take the minimum value of all possibilities, which becomes the value of $f[i][j]$. + +In summary, we can derive the state transition equation: + +$$ +f[i][j]= +\begin{cases} +0, & i+1=j \\ +\infty, & i+1 @@ -318,7 +363,11 @@ function minScoreTriangulation(values: number[]): number { -### Solution 3 +### Solution 3: Dynamic Programming (Alternative Implementation) + +In Solution 2, we mentioned two enumeration strategies. Here, we use the second strategy: enumerate the interval length $l$ from small to large, where $3 \leq l \leq n$. Then, enumerate the left endpoint $i$ of the interval, and the right endpoint can be calculated as $j = i + l - 1$. + +The time complexity is $O(n^3)$, and the space complexity is $O(n^2)$, where $n$ is the number of vertices in the polygon. diff --git a/solution/1000-1099/1041.Robot Bounded In Circle/README.md b/solution/1000-1099/1041.Robot Bounded In Circle/README.md index ebba2ee50f149..f455c915e819c 100644 --- a/solution/1000-1099/1041.Robot Bounded In Circle/README.md +++ b/solution/1000-1099/1041.Robot Bounded In Circle/README.md @@ -107,20 +107,20 @@ tags: 我们可以模拟机器人的行走过程,用一个变量 $k$ 表示机器人的方向,初始值为 $0$,表示机器人面向北方。变量 $k$ 的取值范围为 $[0, 3]$,分别表示机器人面向北、西、南、东。另外,我们用一个长度为 $4$ 的数组 $dist$ 记录机器人在四个方向上行走的距离,初始值为 $[0, 0, 0, 0]$。 -遍历指令字符串 `instructions`,如果当前指令为 `'L'`,那么机器人转向西方,即 $k = (k + 1) \bmod 4$;如果当前指令为 `'R'`,那么机器人转向东方,即 $k = (k + 3) \bmod 4$;否则,机器人在当前方向上行走一步,即 $dist[k]++$。 +遍历指令字符串 $\textit{instructions}$,如果当前指令为 `'L'`,那么机器人转向西方,即 $k = (k + 1) \bmod 4$;如果当前指令为 `'R'`,那么机器人转向东方,即 $k = (k + 3) \bmod 4$;否则,机器人在当前方向上行走一步,即 $dist[k]++$。 -如果给定的指令字符串 `instructions` 执行一遍后,使得机器人最终回到原点,即 $dist[0] = dist[2]$ 且 $dist[1] = dist[3]$,那么机器人一定会进入循环。因为无论重复多少次指令,机器人都回到了原点,所以机器人一定会进入循环。 +如果给定的指令字符串 $\textit{instructions}$ 执行一遍后,使得机器人最终回到原点,即 $dist[0] = dist[2]$ 且 $dist[1] = dist[3]$,那么机器人一定会进入循环。因为无论重复多少次指令,机器人都回到了原点,所以机器人一定会进入循环。 -如果给定的指令字符串 `instructions` 执行一遍后,机器人没回到原点,不妨假设此时机器人位于 $(x, y)$,且方向为 $k$。 +如果给定的指令字符串 $\textit{instructions}$ 执行一遍后,机器人没回到原点,不妨假设此时机器人位于 $(x, y)$,且方向为 $k$。 - 若 $k=0$,即机器人面向北方,那么执行第二遍指令后,坐标变化量是 $(x, y)$;继续执行第三遍指令后,坐标变化量还是 $(x, y)$...累加这些变化量,机器人最终会到 $(n \times x, n \times y)$,其中 $n$ 是一个正整数。由于机器人最终没有回到原点,即 $x \neq 0$ 或 $y \neq 0$,所以 $n \times x \neq 0$ 或 $n \times y \neq 0$,因此机器人不会进入循环; - 若 $k=1$,即机器人面向西方,那么机器人执行第二遍指令后,坐标变化量是 $(-y, x)$;继续执行第三遍执行后,坐标变化量是 $(-x, -y)$;继续执行第四遍指令后,坐标变化量是 $(y, -x)$。累加这些坐标变化量,我们可以发现,机器人最终会回到原点 $(0, 0)$; - 若 $k=2$,即机器人面向南方,那么执行第二遍指令后,坐标变化量是 $(-x, -y)$,累加这两次坐标变化量,我们可以发现,机器人最终会回到原点 $(0, 0)$; - 若 $k=3$,即机器人面向东方,那么执行第二遍指令后,坐标变化量是 $(y, -x)$;继续执行第三遍指令后,坐标变化量是 $(-x, -y)$;继续执行第四遍指令后,坐标变化量是 $(-y, x)$。累加这些坐标变化量,我们可以发现,机器人最终会回到原点 $(0, 0)$。 -综上所述,如果给定的指令字符串 `instructions` 执行一遍后,机器人回到了原点,或者机器人的方向与初始方向不同,那么机器人一定会进入循环。 +综上所述,如果给定的指令字符串 $\textit{instructions}$ 执行一遍后,机器人回到了原点,或者机器人的方向与初始方向不同,那么机器人一定会进入循环。 -时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为指令字符串 `instructions` 的长度。 +时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为指令字符串 $\textit{instructions}$ 的长度。 diff --git a/solution/1000-1099/1041.Robot Bounded In Circle/README_EN.md b/solution/1000-1099/1041.Robot Bounded In Circle/README_EN.md index a33cd28cfc5ff..228fc5525573d 100644 --- a/solution/1000-1099/1041.Robot Bounded In Circle/README_EN.md +++ b/solution/1000-1099/1041.Robot Bounded In Circle/README_EN.md @@ -102,7 +102,24 @@ Based on that, we return true. -### Solution 1 +### Solution 1: Simulation + +We can simulate the robot's movement. Use a variable $k$ to represent the robot's direction, initialized to $0$, which means the robot is facing north. The variable $k$ can take values in the range $[0, 3]$, representing the robot facing north, west, south, and east, respectively. Additionally, we use an array $dist$ of length $4$ to record the distance the robot travels in the four directions, initialized to $[0, 0, 0, 0]$. + +Traverse the instruction string $\textit{instructions}$. If the current instruction is `'L'`, the robot turns west, i.e., $k = (k + 1) \bmod 4$; if the instruction is `'R'`, the robot turns east, i.e., $k = (k + 3) \bmod 4$; otherwise, the robot moves one step in the current direction, i.e., $dist[k]++$. + +If the given instruction string $\textit{instructions}$ is executed once and the robot returns to the origin, i.e., $dist[0] = dist[2]$ and $dist[1] = dist[3]$, then the robot will definitely enter a loop. This is because no matter how many times the instructions are repeated, the robot always returns to the origin, so it must enter a loop. + +If the given instruction string $\textit{instructions}$ is executed once and the robot does not return to the origin, suppose the robot is at $(x, y)$ and its direction is $k$. + +- If $k=0$, i.e., the robot is facing north, then after executing the instructions a second time, the coordinate change is $(x, y)$; after executing the instructions a third time, the coordinate change is still $(x, y)$... Accumulating these changes, the robot will eventually reach $(n \times x, n \times y)$, where $n$ is a positive integer. Since the robot does not return to the origin, i.e., $x \neq 0$ or $y \neq 0$, it follows that $n \times x \neq 0$ or $n \times y \neq 0$, so the robot will not enter a loop; +- If $k=1$, i.e., the robot is facing west, then after executing the instructions a second time, the coordinate change is $(-y, x)$; after executing the instructions a third time, the coordinate change is $(-x, -y)$; after executing the instructions a fourth time, the coordinate change is $(y, -x)$. Accumulating these coordinate changes, we find that the robot will eventually return to the origin $(0, 0)$; +- If $k=2$, i.e., the robot is facing south, then after executing the instructions a second time, the coordinate change is $(-x, -y)$. Accumulating these two coordinate changes, we find that the robot will eventually return to the origin $(0, 0)$; +- If $k=3$, i.e., the robot is facing east, then after executing the instructions a second time, the coordinate change is $(y, -x)$; after executing the instructions a third time, the coordinate change is $(-x, -y)$; after executing the instructions a fourth time, the coordinate change is $(-y, x)$. Accumulating these coordinate changes, we find that the robot will eventually return to the origin $(0, 0)$. + +In conclusion, if the given instruction string $\textit{instructions}$ is executed once and the robot returns to the origin, or if the robot's direction is different from the initial direction, then the robot will definitely enter a loop. + +The time complexity is $O(n)$, and the space complexity is $O(1)$, where $n$ is the length of the instruction string $\textit{instructions}$. diff --git a/solution/1000-1099/1042.Flower Planting With No Adjacent/README.md b/solution/1000-1099/1042.Flower Planting With No Adjacent/README.md index ee54ba5be9491..bb6ffe8767ca4 100644 --- a/solution/1000-1099/1042.Flower Planting With No Adjacent/README.md +++ b/solution/1000-1099/1042.Flower Planting With No Adjacent/README.md @@ -77,7 +77,7 @@ tags: ### 方法一:枚举 -我们先根据数组 $paths$ 构建图 $g$,其中 $g[x]$ 表示与花园 $x$ 相邻的花园列表。 +我们先根据数组 $\textit{paths}$ 构建图 $g$,其中 $g[x]$ 表示与花园 $x$ 相邻的花园列表。 接下来,对于每个花园 $x$,我们先找出与 $x$ 相邻的花园 $y$,并将 $y$ 花园中种植的花的种类标记为已使用。然后我们从花的种类 $1$ 开始枚举,直到找到一个未被使用的花的种类 $c$,将 $c$ 标记为 $x$ 花园中种植的花的种类,然后继续枚举下一个花园。 @@ -200,14 +200,14 @@ func gardenNoAdj(n int, paths [][]int) []int { ```ts function gardenNoAdj(n: number, paths: number[][]): number[] { - const g: number[][] = new Array(n).fill(0).map(() => []); + const g: number[][] = Array.from({ length: n }, () => []); for (const [x, y] of paths) { g[x - 1].push(y - 1); g[y - 1].push(x - 1); } - const ans: number[] = new Array(n).fill(0); + const ans: number[] = Array(n).fill(0); for (let x = 0; x < n; ++x) { - const used: boolean[] = new Array(5).fill(false); + const used: boolean[] = Array(5).fill(false); for (const y of g[x]) { used[ans[y]] = true; } @@ -222,6 +222,38 @@ function gardenNoAdj(n: number, paths: number[][]): number[] { } ``` +#### Rust + +```rust +impl Solution { + pub fn garden_no_adj(n: i32, paths: Vec>) -> Vec { + let n = n as usize; + let mut g = vec![vec![]; n]; + + for path in paths { + let (x, y) = (path[0] as usize - 1, path[1] as usize - 1); + g[x].push(y); + g[y].push(x); + } + + let mut ans = vec![0; n]; + for x in 0..n { + let mut used = [false; 5]; + for &y in &g[x] { + used[ans[y] as usize] = true; + } + for c in 1..5 { + if !used[c] { + ans[x] = c as i32; + break; + } + } + } + ans + } +} +``` + diff --git a/solution/1000-1099/1042.Flower Planting With No Adjacent/README_EN.md b/solution/1000-1099/1042.Flower Planting With No Adjacent/README_EN.md index ea2ac2fd5070a..c299b2cab2a93 100644 --- a/solution/1000-1099/1042.Flower Planting With No Adjacent/README_EN.md +++ b/solution/1000-1099/1042.Flower Planting With No Adjacent/README_EN.md @@ -73,7 +73,15 @@ Hence, [1,2,3] is a valid answer. Other valid answers include [1,2,4], [1,4,2], -### Solution 1 +### Solution 1: Enumeration + +We first construct a graph $g$ based on the array $\textit{paths}$, where $g[x]$ represents the list of gardens adjacent to garden $x$. + +Next, for each garden $x$, we first find the gardens $y$ adjacent to $x$ and mark the types of flowers planted in garden $y$ as used. Then, we enumerate the flower types starting from $1$ until we find a flower type $c$ that has not been used. We assign $c$ as the flower type for garden $x$ and continue to the next garden. + +After the enumeration is complete, we return the result. + +The time complexity is $O(n + m)$, and the space complexity is $O(n + m)$, where $n$ is the number of gardens and $m$ is the number of paths. @@ -190,14 +198,14 @@ func gardenNoAdj(n int, paths [][]int) []int { ```ts function gardenNoAdj(n: number, paths: number[][]): number[] { - const g: number[][] = new Array(n).fill(0).map(() => []); + const g: number[][] = Array.from({ length: n }, () => []); for (const [x, y] of paths) { g[x - 1].push(y - 1); g[y - 1].push(x - 1); } - const ans: number[] = new Array(n).fill(0); + const ans: number[] = Array(n).fill(0); for (let x = 0; x < n; ++x) { - const used: boolean[] = new Array(5).fill(false); + const used: boolean[] = Array(5).fill(false); for (const y of g[x]) { used[ans[y]] = true; } @@ -212,6 +220,38 @@ function gardenNoAdj(n: number, paths: number[][]): number[] { } ``` +#### Rust + +```rust +impl Solution { + pub fn garden_no_adj(n: i32, paths: Vec>) -> Vec { + let n = n as usize; + let mut g = vec![vec![]; n]; + + for path in paths { + let (x, y) = (path[0] as usize - 1, path[1] as usize - 1); + g[x].push(y); + g[y].push(x); + } + + let mut ans = vec![0; n]; + for x in 0..n { + let mut used = [false; 5]; + for &y in &g[x] { + used[ans[y] as usize] = true; + } + for c in 1..5 { + if !used[c] { + ans[x] = c as i32; + break; + } + } + } + ans + } +} +``` + diff --git a/solution/1000-1099/1042.Flower Planting With No Adjacent/Solution.rs b/solution/1000-1099/1042.Flower Planting With No Adjacent/Solution.rs new file mode 100644 index 0000000000000..8b459ac0191af --- /dev/null +++ b/solution/1000-1099/1042.Flower Planting With No Adjacent/Solution.rs @@ -0,0 +1,27 @@ +impl Solution { + pub fn garden_no_adj(n: i32, paths: Vec>) -> Vec { + let n = n as usize; + let mut g = vec![vec![]; n]; + + for path in paths { + let (x, y) = (path[0] as usize - 1, path[1] as usize - 1); + g[x].push(y); + g[y].push(x); + } + + let mut ans = vec![0; n]; + for x in 0..n { + let mut used = [false; 5]; + for &y in &g[x] { + used[ans[y] as usize] = true; + } + for c in 1..5 { + if !used[c] { + ans[x] = c as i32; + break; + } + } + } + ans + } +} diff --git a/solution/1000-1099/1042.Flower Planting With No Adjacent/Solution.ts b/solution/1000-1099/1042.Flower Planting With No Adjacent/Solution.ts index 55699e2db0d13..10ab2958eb83c 100644 --- a/solution/1000-1099/1042.Flower Planting With No Adjacent/Solution.ts +++ b/solution/1000-1099/1042.Flower Planting With No Adjacent/Solution.ts @@ -1,12 +1,12 @@ function gardenNoAdj(n: number, paths: number[][]): number[] { - const g: number[][] = new Array(n).fill(0).map(() => []); + const g: number[][] = Array.from({ length: n }, () => []); for (const [x, y] of paths) { g[x - 1].push(y - 1); g[y - 1].push(x - 1); } - const ans: number[] = new Array(n).fill(0); + const ans: number[] = Array(n).fill(0); for (let x = 0; x < n; ++x) { - const used: boolean[] = new Array(5).fill(false); + const used: boolean[] = Array(5).fill(false); for (const y of g[x]) { used[ans[y]] = true; }