mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-12 21:50:49 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
56
107寻找存在的路径Java代码
Normal file
56
107寻找存在的路径Java代码
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
JAVA:
|
||||||
|
|
||||||
|
```Java
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Main{
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int N, M;
|
||||||
|
Scanner scanner = new Scanner(System.in);
|
||||||
|
N = scanner.nextInt();
|
||||||
|
M = scanner.nextInt();
|
||||||
|
DisJoint disJoint = new DisJoint(N + 1);
|
||||||
|
for (int i = 0; i < M; ++i) {
|
||||||
|
disJoint.join(scanner.nextInt(), scanner.nextInt());
|
||||||
|
}
|
||||||
|
if(disJoint.isSame(scanner.nextInt(), scanner.nextInt())) {
|
||||||
|
System.out.println("1");
|
||||||
|
} else {
|
||||||
|
System.out.println("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//并查集模板
|
||||||
|
class DisJoint{
|
||||||
|
private int[] father;
|
||||||
|
|
||||||
|
public DisJoint(int N) {
|
||||||
|
father = new int[N];
|
||||||
|
for (int i = 0; i < N; ++i){
|
||||||
|
father[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int find(int n) {
|
||||||
|
return n == father[n] ? n : (father[n] = find(father[n]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void join (int n, int m) {
|
||||||
|
n = find(n);
|
||||||
|
m = find(m);
|
||||||
|
if (n == m) return;
|
||||||
|
father[m] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSame(int n, int m){
|
||||||
|
n = find(n);
|
||||||
|
m = find(m);
|
||||||
|
return n == m;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
@ -249,6 +249,29 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
```
|
||||||
|
// 解法3
|
||||||
|
class Solution {
|
||||||
|
public int canCompleteCircuit(int[] gas, int[] cost) {
|
||||||
|
int tank = 0; // 当前油量
|
||||||
|
int totalGas = 0; // 总加油量
|
||||||
|
int totalCost = 0; // 总油耗
|
||||||
|
int start = 0; // 起点
|
||||||
|
for (int i = 0; i < gas.length; i++) {
|
||||||
|
totalGas += gas[i];
|
||||||
|
totalCost += cost[i];
|
||||||
|
|
||||||
|
tank += gas[i] - cost[i];
|
||||||
|
if (tank < 0) { // tank 变为负数 意味着 从0到i之间出发都不能顺利环路一周,因为在此i点必会没油
|
||||||
|
tank = 0; // reset tank,类似于题目53.最大子树和reset sum
|
||||||
|
start = i + 1; // 起点变为i点往后一位
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (totalCost > totalGas) return -1;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
暴力法
|
暴力法
|
||||||
|
@ -474,6 +474,7 @@ class Solution:
|
|||||||
words = s.split() #type(words) --- list
|
words = s.split() #type(words) --- list
|
||||||
words = words[::-1] # 反转单词
|
words = words[::-1] # 反转单词
|
||||||
return ' '.join(words) #列表转换成字符串
|
return ' '.join(words) #列表转换成字符串
|
||||||
|
```
|
||||||
|
|
||||||
### Go:
|
### Go:
|
||||||
|
|
||||||
|
@ -128,6 +128,36 @@ class Solution {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 版本二:排序数组并贪心地尽可能将负数翻转为正数,再根据剩余的k值调整最小元素的符号,从而最大化数组的总和。
|
||||||
|
class Solution {
|
||||||
|
public int largestSumAfterKNegations(int[] nums, int k) {
|
||||||
|
if (nums.length == 1) return nums[0];
|
||||||
|
|
||||||
|
// 排序:先把负数处理了
|
||||||
|
Arrays.sort(nums);
|
||||||
|
|
||||||
|
for (int i = 0; i < nums.length && k > 0; i++) { // 贪心点, 通过负转正, 消耗尽可能多的k
|
||||||
|
if (nums[i] < 0) {
|
||||||
|
nums[i] = -nums[i];
|
||||||
|
k--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出循环, k > 0 || k < 0 (k消耗完了不用讨论)
|
||||||
|
if (k % 2 == 1) { // k > 0 && k is odd:对于负数:负-正-负-正
|
||||||
|
Arrays.sort(nums); // 再次排序得到剩余的负数,或者最小的正数
|
||||||
|
nums[0] = -nums[0];
|
||||||
|
}
|
||||||
|
// k > 0 && k is even,flip数字不会产生影响: 对于负数: 负-正-负;对于正数:正-负-正
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
for (int num : nums) { // 计算最大和
|
||||||
|
sum += num;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
5 6 2
|
5 6 2
|
||||||
5 7 1
|
5 7 1
|
||||||
6 7 1
|
6 7 1
|
||||||
```
|
```
|
||||||
|
|
||||||
输出示例:
|
输出示例:
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ kruscal的思路:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
--------
|
--------
|
||||||
|
|
||||||
选边(4,5),节点4 和 节点 5 不在同一个集合,生成树可以添加边(4,5) ,并将节点4,节点5 放到同一个集合。
|
选边(4,5),节点4 和 节点 5 不在同一个集合,生成树可以添加边(4,5) ,并将节点4,节点5 放到同一个集合。
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ kruscal的思路:
|
|||||||
|
|
||||||
**大家判断两个节点是否在同一个集合,就看图中两个节点是否有绿色的粗线连着就行**
|
**大家判断两个节点是否在同一个集合,就看图中两个节点是否有绿色的粗线连着就行**
|
||||||
|
|
||||||
------
|
------
|
||||||
|
|
||||||
(这里在强调一下,以下选边是按照上面排序好的边的数组来选择的)
|
(这里在强调一下,以下选边是按照上面排序好的边的数组来选择的)
|
||||||
|
|
||||||
@ -95,13 +95,13 @@ kruscal的思路:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
---------
|
---------
|
||||||
|
|
||||||
选边(2,6),节点2 和 节点6 不在同一个集合,生成树添加边(2,6),并将节点2,节点6 放到同一个集合。
|
选边(2,6),节点2 和 节点6 不在同一个集合,生成树添加边(2,6),并将节点2,节点6 放到同一个集合。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
--------
|
--------
|
||||||
|
|
||||||
选边(3,4),节点3 和 节点4 不在同一个集合,生成树添加边(3,4),并将节点3,节点4 放到同一个集合。
|
选边(3,4),节点3 和 节点4 不在同一个集合,生成树添加边(3,4),并将节点3,节点4 放到同一个集合。
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ kruscal的思路:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
选边(5,7),节点5 和 节点7 在同一个集合,不做计算。
|
选边(5,7),节点5 和 节点7 在同一个集合,不做计算。
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ kruscal的思路:
|
|||||||
后面遍历 边(3,2),(2,4),(5,6) 同理,都因两个节点已经在同一集合,不做计算。
|
后面遍历 边(3,2),(2,4),(5,6) 同理,都因两个节点已经在同一集合,不做计算。
|
||||||
|
|
||||||
|
|
||||||
-------
|
-------
|
||||||
|
|
||||||
此时 我们就已经生成了一个最小生成树,即:
|
此时 我们就已经生成了一个最小生成树,即:
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ int main() {
|
|||||||
|
|
||||||
如果题目要求将最小生成树的边输出的话,应该怎么办呢?
|
如果题目要求将最小生成树的边输出的话,应该怎么办呢?
|
||||||
|
|
||||||
Kruskal 算法 输出边的话,相对prim 要容易很多,因为 Kruskal 本来就是直接操作边,边的结构自然清晰,不用像 prim一样 需要再节点练成线输出边 (因为prim是对节点操作,而 Kruskal是对边操作,这是本质区别)
|
Kruskal 算法 输出边的话,相对prim 要容易很多,因为 Kruskal 本来就是直接操作边,边的结构自然清晰,不用像 prim一样 需要再将节点连成线输出边 (因为prim是对节点操作,而 Kruskal是对边操作,这是本质区别)
|
||||||
|
|
||||||
本题中,边的结构为:
|
本题中,边的结构为:
|
||||||
|
|
||||||
|
@ -605,6 +605,125 @@ if __name__ == "__main__":
|
|||||||
```
|
```
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
|
#### 邻接矩阵写法
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var result [][]int // 收集符合条件的路径
|
||||||
|
var path []int // 1节点到终点的路径
|
||||||
|
|
||||||
|
func dfs(graph [][]int, x, n int) {
|
||||||
|
// 当前遍历的节点x 到达节点n
|
||||||
|
if x == n { // 找到符合条件的一条路径
|
||||||
|
temp := make([]int, len(path))
|
||||||
|
copy(temp, path)
|
||||||
|
result = append(result, temp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 1; i <= n; i++ { // 遍历节点x链接的所有节点
|
||||||
|
if graph[x][i] == 1 { // 找到 x链接的节点
|
||||||
|
path = append(path, i) // 遍历到的节点加入到路径中来
|
||||||
|
dfs(graph, i, n) // 进入下一层递归
|
||||||
|
path = path[:len(path)-1] // 回溯,撤销本节点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var n, m int
|
||||||
|
fmt.Scanf("%d %d", &n, &m)
|
||||||
|
|
||||||
|
// 节点编号从1到n,所以申请 n+1 这么大的数组
|
||||||
|
graph := make([][]int, n+1)
|
||||||
|
for i := range graph {
|
||||||
|
graph[i] = make([]int, n+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < m; i++ {
|
||||||
|
var s, t int
|
||||||
|
fmt.Scanf("%d %d", &s, &t)
|
||||||
|
// 使用邻接矩阵表示无向图,1 表示 s 与 t 是相连的
|
||||||
|
graph[s][t] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
path = append(path, 1) // 无论什么路径已经是从1节点出发
|
||||||
|
dfs(graph, 1, n) // 开始遍历
|
||||||
|
|
||||||
|
// 输出结果
|
||||||
|
if len(result) == 0 {
|
||||||
|
fmt.Println(-1)
|
||||||
|
} else {
|
||||||
|
for _, pa := range result {
|
||||||
|
for i := 0; i < len(pa)-1; i++ {
|
||||||
|
fmt.Print(pa[i], " ")
|
||||||
|
}
|
||||||
|
fmt.Println(pa[len(pa)-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 邻接表写法
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var result [][]int
|
||||||
|
var path []int
|
||||||
|
|
||||||
|
func dfs(graph [][]int, x, n int) {
|
||||||
|
if x == n {
|
||||||
|
temp := make([]int, len(path))
|
||||||
|
copy(temp, path)
|
||||||
|
result = append(result, temp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, i := range graph[x] {
|
||||||
|
path = append(path, i)
|
||||||
|
dfs(graph, i, n)
|
||||||
|
path = path[:len(path)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var n, m int
|
||||||
|
fmt.Scanf("%d %d", &n, &m)
|
||||||
|
|
||||||
|
graph := make([][]int, n+1)
|
||||||
|
for i := 0; i <= n; i++ {
|
||||||
|
graph[i] = make([]int, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
for m > 0 {
|
||||||
|
var s, t int
|
||||||
|
fmt.Scanf("%d %d", &s, &t)
|
||||||
|
graph[s] = append(graph[s], t)
|
||||||
|
m--
|
||||||
|
}
|
||||||
|
|
||||||
|
path = append(path, 1)
|
||||||
|
dfs(graph, 1, n)
|
||||||
|
|
||||||
|
if len(result) == 0 {
|
||||||
|
fmt.Println(-1)
|
||||||
|
} else {
|
||||||
|
for _, pa := range result {
|
||||||
|
for i := 0; i < len(pa)-1; i++ {
|
||||||
|
fmt.Print(pa[i], " ")
|
||||||
|
}
|
||||||
|
fmt.Println(pa[len(pa)-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Rust
|
### Rust
|
||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
|
@ -322,6 +322,72 @@ print(result)
|
|||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
|
``` go
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
var dir = [][]int{{0, 1}, {1, 0}, {-1, 0}, {0, -1}} // 四个方向
|
||||||
|
|
||||||
|
func dfs(grid [][]int, visited [][]bool, x, y int) {
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
nextx := x + dir[i][0]
|
||||||
|
nexty := y + dir[i][1]
|
||||||
|
if nextx < 0 || nextx >= len(grid) || nexty < 0 || nexty >= len(grid[0]) {
|
||||||
|
continue // 越界了,直接跳过
|
||||||
|
}
|
||||||
|
if !visited[nextx][nexty] && grid[nextx][nexty] == 1 { // 没有访问过的 同时 是陆地的
|
||||||
|
visited[nextx][nexty] = true
|
||||||
|
count++
|
||||||
|
dfs(grid, visited, nextx, nexty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var n, m int
|
||||||
|
fmt.Scan(&n, &m)
|
||||||
|
|
||||||
|
grid := make([][]int, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
grid[i] = make([]int, m)
|
||||||
|
for j := 0; j < m; j++ {
|
||||||
|
fmt.Scan(&grid[i][j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visited := make([][]bool, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
visited[i] = make([]bool, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := 0
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
for j := 0; j < m; j++ {
|
||||||
|
if !visited[i][j] && grid[i][j] == 1 {
|
||||||
|
count = 1 // 因为dfs处理下一个节点,所以这里遇到陆地了就先计数,dfs处理接下来的相邻陆地
|
||||||
|
visited[i][j] = true
|
||||||
|
dfs(grid, visited, i, j)
|
||||||
|
if count > result {
|
||||||
|
result = count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Rust
|
### Rust
|
||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
@ -420,6 +486,65 @@ const bfs = (graph, visited, x, y) => {
|
|||||||
|
|
||||||
### PhP
|
### PhP
|
||||||
|
|
||||||
|
``` php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function dfs(&$grid, &$visited, $x, $y, &$count, &$dir) {
|
||||||
|
for ($i = 0; $i < 4; $i++) {
|
||||||
|
$nextx = $x + $dir[$i][0];
|
||||||
|
$nexty = $y + $dir[$i][1];
|
||||||
|
if ($nextx < 0 || $nextx >= count($grid) || $nexty < 0 || $nexty >= count($grid[0])) continue; // 越界了,直接跳过
|
||||||
|
if (!$visited[$nextx][$nexty] && $grid[$nextx][$nexty] == 1) { // 没有访问过的 同时 是陆地的
|
||||||
|
$visited[$nextx][$nexty] = true;
|
||||||
|
$count++;
|
||||||
|
dfs($grid, $visited, $nextx, $nexty, $count, $dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function
|
||||||
|
function main() {
|
||||||
|
$input = trim(fgets(STDIN));
|
||||||
|
list($n, $m) = explode(' ', $input);
|
||||||
|
|
||||||
|
$grid = [];
|
||||||
|
for ($i = 0; $i < $n; $i++) {
|
||||||
|
$input = trim(fgets(STDIN));
|
||||||
|
$grid[] = array_map('intval', explode(' ', $input));
|
||||||
|
}
|
||||||
|
|
||||||
|
$visited = [];
|
||||||
|
for ($i = 0; $i < $n; $i++) {
|
||||||
|
$visited[] = array_fill(0, $m, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = 0;
|
||||||
|
$count = 0;
|
||||||
|
$dir = [[0, 1], [1, 0], [-1, 0], [0, -1]]; // 四个方向
|
||||||
|
|
||||||
|
for ($i = 0; $i < $n; $i++) {
|
||||||
|
for ($j = 0; $j < $m; $j++) {
|
||||||
|
if (!$visited[$i][$j] && $grid[$i][$j] == 1) {
|
||||||
|
$count = 1; // 因为dfs处理下一个节点,所以这里遇到陆地了就先计数,dfs处理接下来的相邻陆地
|
||||||
|
$visited[$i][$j] = true;
|
||||||
|
dfs($grid, $visited, $i, $j, $count, $dir); // 将与其链接的陆地都标记上 true
|
||||||
|
$result = max($result, $count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $result . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Swift
|
### Swift
|
||||||
|
|
||||||
### Scala
|
### Scala
|
||||||
|
@ -185,6 +185,77 @@ int main() {
|
|||||||
|
|
||||||
### Java
|
### Java
|
||||||
|
|
||||||
|
``` java
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
private static int count = 0;
|
||||||
|
private static final int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 四个方向
|
||||||
|
|
||||||
|
private static void bfs(int[][] grid, int x, int y) {
|
||||||
|
Queue<int[]> que = new LinkedList<>();
|
||||||
|
que.add(new int[]{x, y});
|
||||||
|
grid[x][y] = 0; // 只要加入队列,立刻标记
|
||||||
|
count++;
|
||||||
|
while (!que.isEmpty()) {
|
||||||
|
int[] cur = que.poll();
|
||||||
|
int curx = cur[0];
|
||||||
|
int cury = cur[1];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int nextx = curx + dir[i][0];
|
||||||
|
int nexty = cury + dir[i][1];
|
||||||
|
if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) continue; // 越界了,直接跳过
|
||||||
|
if (grid[nextx][nexty] == 1) {
|
||||||
|
que.add(new int[]{nextx, nexty});
|
||||||
|
count++;
|
||||||
|
grid[nextx][nexty] = 0; // 只要加入队列立刻标记
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Scanner scanner = new Scanner(System.in);
|
||||||
|
int n = scanner.nextInt();
|
||||||
|
int m = scanner.nextInt();
|
||||||
|
int[][] grid = new int[n][m];
|
||||||
|
|
||||||
|
// 读取网格
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
for (int j = 0; j < m; j++) {
|
||||||
|
grid[i][j] = scanner.nextInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从左侧边,和右侧边向中间遍历
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if (grid[i][0] == 1) bfs(grid, i, 0);
|
||||||
|
if (grid[i][m - 1] == 1) bfs(grid, i, m - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从上边和下边向中间遍历
|
||||||
|
for (int j = 0; j < m; j++) {
|
||||||
|
if (grid[0][j] == 1) bfs(grid, 0, j);
|
||||||
|
if (grid[n - 1][j] == 1) bfs(grid, n - 1, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
for (int j = 0; j < m; j++) {
|
||||||
|
if (grid[i][j] == 1) bfs(grid, i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
```python
|
```python
|
||||||
from collections import deque
|
from collections import deque
|
||||||
@ -238,6 +309,97 @@ print(count)
|
|||||||
```
|
```
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
|
``` go
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
var dir = [4][2]int{{0, 1}, {1, 0}, {-1, 0}, {0, -1}} // 四个方向
|
||||||
|
|
||||||
|
func bfs(grid [][]int, x, y int) {
|
||||||
|
queue := [][2]int{{x, y}}
|
||||||
|
grid[x][y] = 0 // 只要加入队列,立刻标记
|
||||||
|
count++
|
||||||
|
|
||||||
|
for len(queue) > 0 {
|
||||||
|
cur := queue[0]
|
||||||
|
queue = queue[1:]
|
||||||
|
curx, cury := cur[0], cur[1]
|
||||||
|
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
nextx := curx + dir[i][0]
|
||||||
|
nexty := cury + dir[i][1]
|
||||||
|
|
||||||
|
if nextx < 0 || nextx >= len(grid) || nexty < 0 || nexty >= len(grid[0]) {
|
||||||
|
continue // 越界了,直接跳过
|
||||||
|
}
|
||||||
|
|
||||||
|
if grid[nextx][nexty] == 1 {
|
||||||
|
queue = append(queue, [2]int{nextx, nexty})
|
||||||
|
count++
|
||||||
|
grid[nextx][nexty] = 0 // 只要加入队列立刻标记
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var n, m int
|
||||||
|
fmt.Scan(&n, &m)
|
||||||
|
|
||||||
|
grid := make([][]int, n)
|
||||||
|
for i := range grid {
|
||||||
|
grid[i] = make([]int, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
for j := 0; j < m; j++ {
|
||||||
|
fmt.Scan(&grid[i][j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从左侧边,和右侧边向中间遍历
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if grid[i][0] == 1 {
|
||||||
|
bfs(grid, i, 0)
|
||||||
|
}
|
||||||
|
if grid[i][m-1] == 1 {
|
||||||
|
bfs(grid, i, m-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从上边和下边向中间遍历
|
||||||
|
for j := 0; j < m; j++ {
|
||||||
|
if grid[0][j] == 1 {
|
||||||
|
bfs(grid, 0, j)
|
||||||
|
}
|
||||||
|
if grid[n-1][j] == 1 {
|
||||||
|
bfs(grid, n-1, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空之前的计数
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
// 遍历所有位置
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
for j := 0; j < m; j++ {
|
||||||
|
if grid[i][j] == 1 {
|
||||||
|
bfs(grid, i, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### Rust
|
### Rust
|
||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
|
@ -362,6 +362,350 @@ public class Main {
|
|||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
|
|
||||||
|
#### 深搜
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const r1 = require('readline').createInterface({ input: process.stdin });
|
||||||
|
// 创建readline接口
|
||||||
|
let iter = r1[Symbol.asyncIterator]();
|
||||||
|
// 创建异步迭代器
|
||||||
|
const readline = async () => (await iter.next()).value;
|
||||||
|
|
||||||
|
let graph // 地图
|
||||||
|
let N, M // 地图大小
|
||||||
|
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向
|
||||||
|
|
||||||
|
|
||||||
|
// 读取输入,初始化地图
|
||||||
|
const initGraph = async () => {
|
||||||
|
let line = await readline();
|
||||||
|
[N, M] = line.split(' ').map(Number);
|
||||||
|
graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
|
||||||
|
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
line = await readline()
|
||||||
|
line = line.split(' ').map(Number)
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
graph[i][j] = line[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 从(x,y)开始深度优先遍历地图
|
||||||
|
* @param {*} graph 地图
|
||||||
|
* @param {*} visited 可访问节点
|
||||||
|
* @param {*} x 开始搜索节点的下标
|
||||||
|
* @param {*} y 开始搜索节点的下标
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
const dfs = (graph, visited, x, y) => {
|
||||||
|
if (visited[x][y]) return
|
||||||
|
visited[x][y] = true // 标记为可访问
|
||||||
|
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
let nextx = x + dir[i][0]
|
||||||
|
let nexty = y + dir[i][1]
|
||||||
|
if (nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue //越界,跳过
|
||||||
|
if (graph[x][y] < graph[nextx][nexty]) continue //不能流过.跳过
|
||||||
|
dfs(graph, visited, nextx, nexty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 判断地图上的(x, y)是否可以到达第一组边界和第二组边界
|
||||||
|
* @param {*} x 坐标
|
||||||
|
* @param {*} y 坐标
|
||||||
|
* @return {*} true可以到达,false不可以到达
|
||||||
|
*/
|
||||||
|
const isResult = (x, y) => {
|
||||||
|
let visited = new Array(N).fill(false).map(() => new Array(M).fill(false))
|
||||||
|
|
||||||
|
let isFirst = false //是否可到达第一边界
|
||||||
|
let isSecond = false //是否可到达第二边界
|
||||||
|
|
||||||
|
// 深搜,将(x, y)可到达的所有节点做标记
|
||||||
|
dfs(graph, visited, x, y)
|
||||||
|
|
||||||
|
// 判断能否到第一边界左边
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
if (visited[i][0]) {
|
||||||
|
isFirst = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断能否到第一边界上边
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
if (visited[0][j]) {
|
||||||
|
isFirst = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断能否到第二边界右边
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
if (visited[i][M - 1]) {
|
||||||
|
isSecond = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断能否到第二边界下边
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
if (visited[N - 1][j]) {
|
||||||
|
isSecond = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isFirst && isSecond
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
|
||||||
|
// 读取输入,初始化地图
|
||||||
|
await initGraph()
|
||||||
|
|
||||||
|
// 遍历地图,判断是否能到达第一组边界和第二组边界
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
if (isResult(i, j)) console.log(i + ' ' + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 广搜-解法一
|
||||||
|
|
||||||
|
```java
|
||||||
|
const r1 = require('readline').createInterface({ input: process.stdin });
|
||||||
|
// 创建readline接口
|
||||||
|
let iter = r1[Symbol.asyncIterator]();
|
||||||
|
// 创建异步迭代器
|
||||||
|
const readline = async () => (await iter.next()).value;
|
||||||
|
|
||||||
|
let graph // 地图
|
||||||
|
let N, M // 地图大小
|
||||||
|
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向
|
||||||
|
|
||||||
|
|
||||||
|
// 读取输入,初始化地图
|
||||||
|
const initGraph = async () => {
|
||||||
|
let line = await readline();
|
||||||
|
[N, M] = line.split(' ').map(Number);
|
||||||
|
graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
|
||||||
|
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
line = await readline()
|
||||||
|
line = line.split(' ').map(Number)
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
graph[i][j] = line[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 从(x,y)开始广度优先遍历地图
|
||||||
|
* @param {*} graph 地图
|
||||||
|
* @param {*} visited 可访问节点
|
||||||
|
* @param {*} x 开始搜索节点的下标
|
||||||
|
* @param {*} y 开始搜索节点的下标
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
const bfs = (graph, visited, x, y) => {
|
||||||
|
let queue = []
|
||||||
|
queue.push([x, y])
|
||||||
|
visited[x][y] = true
|
||||||
|
|
||||||
|
while (queue.length) {
|
||||||
|
const [xx, yy] = queue.shift()
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
let nextx = xx + dir[i][0]
|
||||||
|
let nexty = yy + dir[i][1]
|
||||||
|
if (nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue //越界, 跳过
|
||||||
|
|
||||||
|
// 可访问或者不能流过, 跳过 (注意这里是graph[xx][yy] < graph[nextx][nexty], 不是graph[x][y] < graph[nextx][nexty])
|
||||||
|
if (visited[nextx][nexty] || graph[xx][yy] < graph[nextx][nexty]) continue
|
||||||
|
|
||||||
|
queue.push([nextx, nexty])
|
||||||
|
visited[nextx][nexty] = true
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 判断地图上的(x, y)是否可以到达第一组边界和第二组边界
|
||||||
|
* @param {*} x 坐标
|
||||||
|
* @param {*} y 坐标
|
||||||
|
* @return {*} true可以到达,false不可以到达
|
||||||
|
*/
|
||||||
|
const isResult = (x, y) => {
|
||||||
|
let visited = new Array(N).fill(false).map(() => new Array(M).fill(false))
|
||||||
|
|
||||||
|
let isFirst = false //是否可到达第一边界
|
||||||
|
let isSecond = false //是否可到达第二边界
|
||||||
|
|
||||||
|
// 深搜,将(x, y)可到达的所有节点做标记
|
||||||
|
bfs(graph, visited, x, y)
|
||||||
|
|
||||||
|
// console.log(visited);
|
||||||
|
|
||||||
|
// 判断能否到第一边界左边
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
if (visited[i][0]) {
|
||||||
|
isFirst = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断能否到第一边界上边
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
if (visited[0][j]) {
|
||||||
|
isFirst = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断能否到第二边界右边
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
if (visited[i][M - 1]) {
|
||||||
|
isSecond = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断能否到第二边界下边
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
if (visited[N - 1][j]) {
|
||||||
|
isSecond = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isFirst && isSecond
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
|
||||||
|
// 读取输入,初始化地图
|
||||||
|
await initGraph()
|
||||||
|
|
||||||
|
// 遍历地图,判断是否能到达第一组边界和第二组边界
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
if (isResult(i, j)) console.log(i + ' ' + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 广搜-解法二
|
||||||
|
|
||||||
|
从第一边界和第二边界开始向高处流, 标记可以流到的位置, 两个边界都能到达的位置就是所求结果
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const r1 = require('readline').createInterface({ input: process.stdin });
|
||||||
|
// 创建readline接口
|
||||||
|
let iter = r1[Symbol.asyncIterator]();
|
||||||
|
// 创建异步迭代器
|
||||||
|
const readline = async () => (await iter.next()).value;
|
||||||
|
|
||||||
|
let graph // 地图
|
||||||
|
let N, M // 地图大小
|
||||||
|
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向
|
||||||
|
|
||||||
|
|
||||||
|
// 读取输入,初始化地图
|
||||||
|
const initGraph = async () => {
|
||||||
|
let line = await readline();
|
||||||
|
[N, M] = line.split(' ').map(Number);
|
||||||
|
graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
|
||||||
|
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
line = await readline()
|
||||||
|
line = line.split(' ').map(Number)
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
graph[i][j] = line[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 从(x,y)开始广度优先遍历地图
|
||||||
|
* @param {*} graph 地图
|
||||||
|
* @param {*} visited 可访问节点
|
||||||
|
* @param {*} x 开始搜索节点的下标
|
||||||
|
* @param {*} y 开始搜索节点的下标
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
const bfs = (graph, visited, x, y) => {
|
||||||
|
if(visited[x][y]) return
|
||||||
|
|
||||||
|
let queue = []
|
||||||
|
queue.push([x, y])
|
||||||
|
visited[x][y] = true
|
||||||
|
|
||||||
|
while (queue.length) {
|
||||||
|
const [xx, yy] = queue.shift()
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
let nextx = xx + dir[i][0]
|
||||||
|
let nexty = yy + dir[i][1]
|
||||||
|
if (nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue //越界, 跳过
|
||||||
|
|
||||||
|
// 可访问或者不能流过, 跳过 (注意因为是从边界往高处流, 所以这里是graph[xx][yy] >= graph[nextx][nexty], 还要注意不是graph[xx][yy] >= graph[nextx][nexty])
|
||||||
|
if (visited[nextx][nexty] || graph[xx][yy] >= graph[nextx][nexty]) continue
|
||||||
|
|
||||||
|
queue.push([nextx, nexty])
|
||||||
|
visited[nextx][nexty] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
|
||||||
|
// 读取输入,初始化地图
|
||||||
|
await initGraph()
|
||||||
|
|
||||||
|
// 记录第一边界可到达的节点
|
||||||
|
let firstBorder = new Array(N).fill(false).map(() => new Array(M).fill(false))
|
||||||
|
|
||||||
|
// 记录第二边界可到达的节点
|
||||||
|
let secondBorder = new Array(N).fill(false).map(() => new Array(M).fill(false))
|
||||||
|
|
||||||
|
// 第一边界左边和第二边界右边
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
bfs(graph, firstBorder, i, 0)
|
||||||
|
bfs(graph, secondBorder, i, M - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一边界上边和第二边界下边
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
bfs(graph, firstBorder, 0, j)
|
||||||
|
bfs(graph, secondBorder, N - 1, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历地图,判断是否能到达第一组边界和第二组边界
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
for (let j = 0; j < M; j++) {
|
||||||
|
if (firstBorder[i][j] && secondBorder[i][j]) console.log(i + ' ' + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### TypeScript
|
### TypeScript
|
||||||
|
|
||||||
### PhP
|
### PhP
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
对于情况二,删掉构成环的边就可以了。
|
对于情况三,删掉构成环的边就可以了。
|
||||||
|
|
||||||
|
|
||||||
## 写代码
|
## 写代码
|
||||||
|
@ -69,7 +69,7 @@ for (int i = 0; i < array.size(); i++) {
|
|||||||
|
|
||||||
其实使用双指针也可以解决1.两数之和的问题,只不过1.两数之和求的是两个元素的下标,没法用双指针,如果改成求具体两个元素的数值就可以了,大家可以尝试用双指针做一个leetcode上两数之和的题目,就可以体会到我说的意思了。
|
其实使用双指针也可以解决1.两数之和的问题,只不过1.两数之和求的是两个元素的下标,没法用双指针,如果改成求具体两个元素的数值就可以了,大家可以尝试用双指针做一个leetcode上两数之和的题目,就可以体会到我说的意思了。
|
||||||
|
|
||||||
使用了哈希法解决了两数之和,但是哈希法并不使用于三数之和!
|
使用了哈希法解决了两数之和,但是哈希法并不适用于三数之和!
|
||||||
|
|
||||||
使用哈希法的过程中要把符合条件的三元组放进vector中,然后在去去重,这样是非常费时的,很容易超时,也是三数之和通过率如此之低的根源所在。
|
使用哈希法的过程中要把符合条件的三元组放进vector中,然后在去去重,这样是非常费时的,很容易超时,也是三数之和通过率如此之低的根源所在。
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user