From 358ebfabe7c97675d2d2eb96c91f7c3506864691 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Wed, 3 Dec 2025 22:13:41 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1059 --- .../README.md | 194 +++++++++++------- .../README_EN.md | 190 +++++++++++------ .../Solution.cpp | 50 ++--- .../Solution.go | 29 +-- .../Solution.java | 35 ++-- .../Solution.py | 22 +- .../Solution.ts | 35 ++++ 7 files changed, 354 insertions(+), 201 deletions(-) create mode 100644 solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.ts diff --git a/solution/1000-1099/1059.All Paths from Source Lead to Destination/README.md b/solution/1000-1099/1059.All Paths from Source Lead to Destination/README.md index e2fbf6bf3623e..ee613f7594bbe 100644 --- a/solution/1000-1099/1059.All Paths from Source Lead to Destination/README.md +++ b/solution/1000-1099/1059.All Paths from Source Lead to Destination/README.md @@ -78,23 +78,25 @@ tags: -### 方法一:记忆化搜索 +### 方法一:DFS -建图,然后从 `source` 出发,进行深度优先搜索: +我们用一个状态数组 $\textit{state}$ 来记录每个节点的状态,其中: -如果遇到了 `destination`,判断此时是否还有出边,如果有出边,返回 `false`,否则返回 `true`。 +- 状态 0 表示该节点未被访问过; +- 状态 1 表示该节点正在被访问; +- 状态 2 表示该节点已经被访问过且可以通向终点。 -如果遇到了环(此前访问过),或者遇到了没有出边的节点,直接返回 `false`。 +我们首先将图构建为邻接表的形式,然后从起点出发进行深度优先搜索(DFS)。在 DFS 过程中: -否则,我们把当前节点标记为已访问,然后对当前节点的所有出边进行深度优先搜索,只要有一条路径无法可以到达 `destination`,就返回 `false`,否则返回 `true`。 +- 如果当前节点的状态为 1,说明我们遇到了一个环,直接返回 $\text{false}$; +- 如果当前节点的状态为 2,说明该节点已经被访问过且可以通向终点,直接返回 $\text{true}$; +- 如果当前节点没有出边,则检查该节点是否为终点,如果是则返回 $\text{true}$,否则返回 $\text{false}$; +- 否则,将当前节点的状态设为 1,递归访问所有相邻节点; +- 如果所有相邻节点都能通向终点,则将当前节点的状态设为 2 并返回 $\text{true}$,否则返回 $\text{false}$。 -过程中我们用一个数组 $f$ 记录每个节点的状态,每个 $f[i]$ 的值有三种,分别表示: +答案为 $\text{dfs}(\text{source})$ 的结果。 -- 对于 $f[i] = 0$,表示节点 $i$ 未被访问; -- 对于 $f[i] = 1$,表示节点 $i$ 已被访问,且可以到达 `destination`; -- 对于 $f[i] = 2$,表示节点 $i$ 已被访问,但无法到达 `destination`。 - -时间复杂度 $O(n)$。其中 $n$ 为节点数。 +时间复杂度 $O(n + m)$,其中 $n$ 和 $m$ 分别为节点数和边数。空间复杂度 $O(n + m)$,用于存储图的邻接表和状态数组。 @@ -105,22 +107,26 @@ class Solution: def leadsToDestination( self, n: int, edges: List[List[int]], source: int, destination: int ) -> bool: - @cache - def dfs(i): - if i == destination: - return not g[i] - if i in vis or not g[i]: - return False - vis.add(i) + def dfs(i: int) -> bool: + if st[i]: + return st[i] == 2 + if not g[i]: + return i == destination + + st[i] = 1 for j in g[i]: if not dfs(j): return False + st[i] = 2 return True - g = defaultdict(list) + g = [[] for _ in range(n)] for a, b in edges: g[a].append(b) - vis = set() + if g[destination]: + return False + + st = [0] * n return dfs(source) ``` @@ -129,40 +135,37 @@ class Solution: ```java class Solution { private List[] g; - private int[] f; - private boolean[] vis; - private int k; + private int[] st; + private int destination; public boolean leadsToDestination(int n, int[][] edges, int source, int destination) { - vis = new boolean[n]; + this.destination = destination; g = new List[n]; - k = destination; - f = new int[n]; - Arrays.setAll(g, key -> new ArrayList<>()); - for (var e : edges) { + Arrays.setAll(g, k -> new ArrayList<>()); + for (int[] e : edges) { g[e[0]].add(e[1]); } + if (!g[destination].isEmpty()) { + return false; + } + st = new int[n]; return dfs(source); } private boolean dfs(int i) { - if (i == k) { - return g[i].isEmpty(); + if (st[i] != 0) { + return st[i] == 2; } - if (f[i] != 0) { - return f[i] == 1; + if (g[i].isEmpty()) { + return i == destination; } - if (vis[i] || g[i].isEmpty()) { - return false; - } - vis[i] = true; + st[i] = 1; for (int j : g[i]) { if (!dfs(j)) { - f[i] = -1; return false; } } - f[i] = 1; + st[i] = 2; return true; } } @@ -173,34 +176,38 @@ class Solution { ```cpp class Solution { public: + vector> g; + vector st; + int destination; + bool leadsToDestination(int n, vector>& edges, int source, int destination) { - vector vis(n); - vector> g(n); - vector f(n); + this->destination = destination; + g.assign(n, {}); for (auto& e : edges) { g[e[0]].push_back(e[1]); } - function dfs = [&](int i) { - if (i == destination) { - return g[i].empty(); - } - if (f[i]) { - return f[i] == 1; - } - if (vis[i] || g[i].empty()) { + if (!g[destination].empty()) { + return false; + } + st.assign(n, 0); + return dfs(source); + } + + bool dfs(int i) { + if (st[i] != 0) { + return st[i] == 2; + } + if (g[i].empty()) { + return i == destination; + } + st[i] = 1; + for (int j : g[i]) { + if (!dfs(j)) { return false; } - vis[i] = true; - for (int j : g[i]) { - if (!dfs(j)) { - f[i] = -1; - return false; - } - } - f[i] = 1; - return true; - }; - return dfs(source); + } + st[i] = 2; + return true; } }; ``` @@ -209,37 +216,78 @@ public: ```go func leadsToDestination(n int, edges [][]int, source int, destination int) bool { - vis := make([]bool, n) g := make([][]int, n) - f := make([]int, n) for _, e := range edges { g[e[0]] = append(g[e[0]], e[1]) } - var dfs func(int) bool + if len(g[destination]) > 0 { + return false + } + + st := make([]int, n) + + var dfs func(i int) bool dfs = func(i int) bool { - if i == destination { - return len(g[i]) == 0 - } - if f[i] != 0 { - return f[i] == 1 + if st[i] != 0 { + return st[i] == 2 } - if vis[i] || len(g[i]) == 0 { - return false + if len(g[i]) == 0 { + return i == destination } - vis[i] = true + st[i] = 1 for _, j := range g[i] { if !dfs(j) { - f[i] = -1 return false } } - f[i] = 1 + st[i] = 2 return true } + return dfs(source) } ``` +#### TypeScript + +```ts +function leadsToDestination( + n: number, + edges: number[][], + source: number, + destination: number, +): boolean { + const g: number[][] = Array.from({ length: n }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + } + if (g[destination].length > 0) { + return false; + } + + const st: number[] = Array(n).fill(0); + + const dfs = (i: number): boolean => { + if (st[i] !== 0) { + return st[i] === 2; + } + if (g[i].length === 0) { + return i === destination; + } + st[i] = 1; + for (const j of g[i]) { + if (!dfs(j)) { + return false; + } + } + st[i] = 2; + return true; + }; + + return dfs(source); +} +``` + diff --git a/solution/1000-1099/1059.All Paths from Source Lead to Destination/README_EN.md b/solution/1000-1099/1059.All Paths from Source Lead to Destination/README_EN.md index e5e4345f6d2ef..4fc668c16d031 100644 --- a/solution/1000-1099/1059.All Paths from Source Lead to Destination/README_EN.md +++ b/solution/1000-1099/1059.All Paths from Source Lead to Destination/README_EN.md @@ -70,7 +70,25 @@ tags: -### Solution 1 +### Solution 1: DFS + +We use a state array $\textit{state}$ to record the status of each node, where: + +- State 0 indicates the node has not been visited; +- State 1 indicates the node is currently being visited; +- State 2 indicates the node has been visited and can lead to the destination. + +First, we build the graph as an adjacency list, then perform a depth-first search (DFS) starting from the source node. During the DFS process: + +- If the current node's state is 1, it means we have encountered a cycle, and we return $\text{false}$ directly; +- If the current node's state is 2, it means the node has been visited and can lead to the destination, and we return $\text{true}$ directly; +- If the current node has no outgoing edges, we check whether it is the destination node. If so, return $\text{true}$; otherwise, return $\text{false}$; +- Otherwise, set the current node's state to 1 and recursively visit all adjacent nodes; +- If all adjacent nodes can lead to the destination, set the current node's state to 2 and return $\text{true}$; otherwise, return $\text{false}$. + +The answer is the result of $\text{dfs}(\text{source})$. + +The time complexity is $O(n + m)$, where $n$ and $m$ are the number of nodes and edges, respectively. The space complexity is $O(n + m)$, used to store the graph's adjacency list and state array. @@ -81,22 +99,26 @@ class Solution: def leadsToDestination( self, n: int, edges: List[List[int]], source: int, destination: int ) -> bool: - @cache - def dfs(i): - if i == destination: - return not g[i] - if i in vis or not g[i]: - return False - vis.add(i) + def dfs(i: int) -> bool: + if st[i]: + return st[i] == 2 + if not g[i]: + return i == destination + + st[i] = 1 for j in g[i]: if not dfs(j): return False + st[i] = 2 return True - g = defaultdict(list) + g = [[] for _ in range(n)] for a, b in edges: g[a].append(b) - vis = set() + if g[destination]: + return False + + st = [0] * n return dfs(source) ``` @@ -105,40 +127,37 @@ class Solution: ```java class Solution { private List[] g; - private int[] f; - private boolean[] vis; - private int k; + private int[] st; + private int destination; public boolean leadsToDestination(int n, int[][] edges, int source, int destination) { - vis = new boolean[n]; + this.destination = destination; g = new List[n]; - k = destination; - f = new int[n]; - Arrays.setAll(g, key -> new ArrayList<>()); - for (var e : edges) { + Arrays.setAll(g, k -> new ArrayList<>()); + for (int[] e : edges) { g[e[0]].add(e[1]); } + if (!g[destination].isEmpty()) { + return false; + } + st = new int[n]; return dfs(source); } private boolean dfs(int i) { - if (i == k) { - return g[i].isEmpty(); - } - if (f[i] != 0) { - return f[i] == 1; + if (st[i] != 0) { + return st[i] == 2; } - if (vis[i] || g[i].isEmpty()) { - return false; + if (g[i].isEmpty()) { + return i == destination; } - vis[i] = true; + st[i] = 1; for (int j : g[i]) { if (!dfs(j)) { - f[i] = -1; return false; } } - f[i] = 1; + st[i] = 2; return true; } } @@ -149,34 +168,38 @@ class Solution { ```cpp class Solution { public: + vector> g; + vector st; + int destination; + bool leadsToDestination(int n, vector>& edges, int source, int destination) { - vector vis(n); - vector> g(n); - vector f(n); + this->destination = destination; + g.assign(n, {}); for (auto& e : edges) { g[e[0]].push_back(e[1]); } - function dfs = [&](int i) { - if (i == destination) { - return g[i].empty(); - } - if (f[i]) { - return f[i] == 1; - } - if (vis[i] || g[i].empty()) { + if (!g[destination].empty()) { + return false; + } + st.assign(n, 0); + return dfs(source); + } + + bool dfs(int i) { + if (st[i] != 0) { + return st[i] == 2; + } + if (g[i].empty()) { + return i == destination; + } + st[i] = 1; + for (int j : g[i]) { + if (!dfs(j)) { return false; } - vis[i] = true; - for (int j : g[i]) { - if (!dfs(j)) { - f[i] = -1; - return false; - } - } - f[i] = 1; - return true; - }; - return dfs(source); + } + st[i] = 2; + return true; } }; ``` @@ -185,37 +208,78 @@ public: ```go func leadsToDestination(n int, edges [][]int, source int, destination int) bool { - vis := make([]bool, n) g := make([][]int, n) - f := make([]int, n) for _, e := range edges { g[e[0]] = append(g[e[0]], e[1]) } - var dfs func(int) bool + if len(g[destination]) > 0 { + return false + } + + st := make([]int, n) + + var dfs func(i int) bool dfs = func(i int) bool { - if i == destination { - return len(g[i]) == 0 - } - if f[i] != 0 { - return f[i] == 1 + if st[i] != 0 { + return st[i] == 2 } - if vis[i] || len(g[i]) == 0 { - return false + if len(g[i]) == 0 { + return i == destination } - vis[i] = true + st[i] = 1 for _, j := range g[i] { if !dfs(j) { - f[i] = -1 return false } } - f[i] = 1 + st[i] = 2 return true } + return dfs(source) } ``` +#### TypeScript + +```ts +function leadsToDestination( + n: number, + edges: number[][], + source: number, + destination: number, +): boolean { + const g: number[][] = Array.from({ length: n }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + } + if (g[destination].length > 0) { + return false; + } + + const st: number[] = Array(n).fill(0); + + const dfs = (i: number): boolean => { + if (st[i] !== 0) { + return st[i] === 2; + } + if (g[i].length === 0) { + return i === destination; + } + st[i] = 1; + for (const j of g[i]) { + if (!dfs(j)) { + return false; + } + } + st[i] = 2; + return true; + }; + + return dfs(source); +} +``` + diff --git a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.cpp b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.cpp index cb1203bfd90e6..918cc27c95421 100644 --- a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.cpp +++ b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.cpp @@ -1,32 +1,36 @@ class Solution { public: + vector> g; + vector st; + int destination; + bool leadsToDestination(int n, vector>& edges, int source, int destination) { - vector vis(n); - vector> g(n); - vector f(n); + this->destination = destination; + g.assign(n, {}); for (auto& e : edges) { g[e[0]].push_back(e[1]); } - function dfs = [&](int i) { - if (i == destination) { - return g[i].empty(); - } - if (f[i]) { - return f[i] == 1; - } - if (vis[i] || g[i].empty()) { + if (!g[destination].empty()) { + return false; + } + st.assign(n, 0); + return dfs(source); + } + + bool dfs(int i) { + if (st[i] != 0) { + return st[i] == 2; + } + if (g[i].empty()) { + return i == destination; + } + st[i] = 1; + for (int j : g[i]) { + if (!dfs(j)) { return false; } - vis[i] = true; - for (int j : g[i]) { - if (!dfs(j)) { - f[i] = -1; - return false; - } - } - f[i] = 1; - return true; - }; - return dfs(source); + } + st[i] = 2; + return true; } -}; \ No newline at end of file +}; diff --git a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.go b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.go index fa168888dcc90..139b805d5b796 100644 --- a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.go +++ b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.go @@ -1,30 +1,31 @@ func leadsToDestination(n int, edges [][]int, source int, destination int) bool { - vis := make([]bool, n) g := make([][]int, n) - f := make([]int, n) for _, e := range edges { g[e[0]] = append(g[e[0]], e[1]) } - var dfs func(int) bool + if len(g[destination]) > 0 { + return false + } + + st := make([]int, n) + + var dfs func(i int) bool dfs = func(i int) bool { - if i == destination { - return len(g[i]) == 0 - } - if f[i] != 0 { - return f[i] == 1 + if st[i] != 0 { + return st[i] == 2 } - if vis[i] || len(g[i]) == 0 { - return false + if len(g[i]) == 0 { + return i == destination } - vis[i] = true + st[i] = 1 for _, j := range g[i] { if !dfs(j) { - f[i] = -1 return false } } - f[i] = 1 + st[i] = 2 return true } + return dfs(source) -} \ No newline at end of file +} diff --git a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.java b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.java index 564c2a81140fe..baa85f1a2557e 100644 --- a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.java +++ b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.java @@ -1,39 +1,36 @@ class Solution { private List[] g; - private int[] f; - private boolean[] vis; - private int k; + private int[] st; + private int destination; public boolean leadsToDestination(int n, int[][] edges, int source, int destination) { - vis = new boolean[n]; + this.destination = destination; g = new List[n]; - k = destination; - f = new int[n]; - Arrays.setAll(g, key -> new ArrayList<>()); - for (var e : edges) { + Arrays.setAll(g, k -> new ArrayList<>()); + for (int[] e : edges) { g[e[0]].add(e[1]); } + if (!g[destination].isEmpty()) { + return false; + } + st = new int[n]; return dfs(source); } private boolean dfs(int i) { - if (i == k) { - return g[i].isEmpty(); + if (st[i] != 0) { + return st[i] == 2; } - if (f[i] != 0) { - return f[i] == 1; - } - if (vis[i] || g[i].isEmpty()) { - return false; + if (g[i].isEmpty()) { + return i == destination; } - vis[i] = true; + st[i] = 1; for (int j : g[i]) { if (!dfs(j)) { - f[i] = -1; return false; } } - f[i] = 1; + st[i] = 2; return true; } -} \ No newline at end of file +} diff --git a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.py b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.py index d4098277b0792..9e3c842c881b4 100644 --- a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.py +++ b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.py @@ -2,20 +2,24 @@ class Solution: def leadsToDestination( self, n: int, edges: List[List[int]], source: int, destination: int ) -> bool: - @cache - def dfs(i): - if i == destination: - return not g[i] - if i in vis or not g[i]: - return False - vis.add(i) + def dfs(i: int) -> bool: + if st[i]: + return st[i] == 2 + if not g[i]: + return i == destination + + st[i] = 1 for j in g[i]: if not dfs(j): return False + st[i] = 2 return True - g = defaultdict(list) + g = [[] for _ in range(n)] for a, b in edges: g[a].append(b) - vis = set() + if g[destination]: + return False + + st = [0] * n return dfs(source) diff --git a/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.ts b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.ts new file mode 100644 index 0000000000000..c2b88c73ffe08 --- /dev/null +++ b/solution/1000-1099/1059.All Paths from Source Lead to Destination/Solution.ts @@ -0,0 +1,35 @@ +function leadsToDestination( + n: number, + edges: number[][], + source: number, + destination: number, +): boolean { + const g: number[][] = Array.from({ length: n }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + } + if (g[destination].length > 0) { + return false; + } + + const st: number[] = Array(n).fill(0); + + const dfs = (i: number): boolean => { + if (st[i] !== 0) { + return st[i] === 2; + } + if (g[i].length === 0) { + return i === destination; + } + st[i] = 1; + for (const j of g[i]) { + if (!dfs(j)) { + return false; + } + } + st[i] = 2; + return true; + }; + + return dfs(source); +}