Merge branch 'master' of github.com:jinbudaily/leetcode-master

This commit is contained in:
jinbudaily
2023-07-23 19:04:36 +08:00
4 changed files with 75 additions and 16 deletions

View File

@ -396,7 +396,7 @@
* [图论:深度优先搜索理论基础](./problems/图论深搜理论基础.md)
* [图论797.所有可能的路径](./problems/0797.所有可能的路径.md)
* [图论:广度优先搜索理论基础](./problems/图论广理论基础.md)
* [图论:广度优先搜索理论基础](./problems/图论广理论基础.md)
* [图论200.岛屿数量.深搜版](./problems/0200.岛屿数量.深搜版.md)
* [图论200.岛屿数量.广搜版](./problems/0200.岛屿数量.广搜版.md)
* [图论695.岛屿的最大面积](./problems/0695.岛屿的最大面积.md)

View File

@ -16,6 +16,7 @@
输入words = ["bella","label","roller"]
输出:["e","l","l"]
示例 2
输入words = ["cool","lock","cook"]

View File

@ -16,13 +16,13 @@
## dfs 与 bfs 区别
提到深度优先搜索dfs就不得不说和广度优先有什么区别bfs
提到深度优先搜索dfs就不得不说和广度优先搜索bfs有什么区别
先来了解dfs的过程很多录友可能对dfs深度优先搜索bfs广度优先搜索分不清。
先给大家说一下两者大概的区别:
* dfs是可一个方向去搜不到黄河不回头直到遇到绝境了搜不下去了换方向(换方向的过程就涉及到了回溯)。
* dfs是可一个方向去搜不到黄河不回头直到遇到绝境了搜不下去了换方向(换方向的过程就涉及到了回溯)。
* bfs是先把本节点所连接的所有节点遍历一遍走到下一个节点的时候再把连接节点的所有节点遍历一遍搜索方向更像是广度四面八方的搜索过程。
当然以上讲的是,大体可以这么理解,接下来 我们详细讲解dfsbfs在用单独一篇文章详细讲解
@ -60,26 +60,26 @@
上图演示中,其实我并没有把 所有的 从节点1 到节点6的dfs深度优先搜索的过程都画出来那样太冗余了但 已经把dfs 关键的地方都涉及到了,关键就两点:
* 搜索方向,是认准一个方向搜,直到碰壁之后换方向
* 搜索方向,是认准一个方向搜,直到碰壁之后换方向
* 换方向是撤销原路径,改为节点链接的下一个路径,回溯的过程。
## 代码框架
因为dfs搜索可一个方向并需要回溯所以用递归的方式来实现是最方便的。
因为dfs搜索可一个方向并需要回溯所以用递归的方式来实现是最方便的。
很多录友对回溯很陌生,建议先看看码随想录,[回溯算法章节](https://programmercarl.com/回溯算法理论基础.html)。
很多录友对回溯很陌生,建议先看看码随想录,[回溯算法章节](https://programmercarl.com/回溯算法理论基础.html)。
有递归的地方就有回溯,那么回溯在哪里呢?
就地递归函数的下面,例如如下代码:
```
```cpp
void dfs(参数) {
处理节点
dfs(图,选择的节点); // 递归
回溯,撤销处理结果
}
```
```
可以看到回溯操作就在递归函数的下面,递归和回溯是相辅相成的。
@ -89,7 +89,7 @@ void dfs(参数) {
我们在回顾一下[回溯法](https://programmercarl.com/回溯算法理论基础.html)的代码框架:
```
```cpp
void backtracking(参数) {
if (终止条件) {
存放结果;
@ -102,11 +102,11 @@ void backtracking(参数) {
}
}
```
```
回溯算法其实就是dfs的过程这里给出dfs的代码框架
```
```cpp
void dfs(参数) {
if (终止条件) {
存放结果;
@ -136,9 +136,9 @@ void dfs(参数) {
1. 确认递归函数,参数
```
```cpp
void dfs(参数)
```
```
通常我们递归的时候,我们递归搜索需要了解哪些参数,其实也可以在写递归函数的时候,发现需要什么参数,再去补充就可以。
@ -146,7 +146,7 @@ void dfs(参数)
例如这样:
```
```cpp
vector<vector<int>> result; // 保存符合条件的所有路径
vector<int> path; // 起点到终点的路径
void dfs (图,目前搜索的节点)
@ -158,7 +158,7 @@ void dfs (图,目前搜索的节点)
终止条件很重要很多同学写dfs的时候之所以容易死循环栈溢出等等这些问题都是因为终止条件没有想清楚。
```
```cpp
if (终止条件) {
存放结果;
return;
@ -173,7 +173,7 @@ if (终止条件) {
一般这里就是一个for循环的操作去遍历 目前搜索节点 所能到的所有节点。
```
```cpp
for (选择:本节点所连接的其他节点) {
处理节点;
dfs(图,选择的节点); // 递归

View File

@ -338,6 +338,64 @@ public class BagProblem {
```
```java
import java.util.Arrays;
public class BagProblem {
public static void main(String[] args) {
int[] weight = {1,3,4};
int[] value = {15,20,30};
int bagSize = 4;
testWeightBagProblem(weight,value,bagSize);
}
/**
* 初始化 dp 数组做了简化(给物品增加冗余维)。这样初始化dp数组默认全为0即可。
* dp[i][j] 表示从下标为[0 - i-1]的物品里任意取放进容量为j的背包价值总和最大是多少。
* 其实是模仿背包重量从 0 开始,背包容量 j 为 0 的话即dp[i][0],无论是选取哪些物品,背包价值总和一定为 0。
* 可选物品也可以从无开始也就是没有物品可选即dp[0][j],这样无论背包容量为多少,背包价值总和一定为 0。
* @param weight 物品的重量
* @param value 物品的价值
* @param bagSize 背包的容量
*/
public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){
// 创建dp数组
int goods = weight.length; // 获取物品的数量
int[][] dp = new int[goods + 1][bagSize + 1]; // 给物品增加冗余维i = 0 表示没有物品可选
// 初始化dp数组默认全为0即可
// 填充dp数组
for (int i = 1; i <= goods; i++) {
for (int j = 1; j <= bagSize; j++) {
if (j < weight[i - 1]) { // i - 1 对应物品 i
/**
* 当前背包的容量都没有当前物品i大的时候是不放物品i的
* 那么前i-1个物品能放下的最大价值就是当前情况的最大价值
*/
dp[i][j] = dp[i - 1][j];
} else {
/**
* 当前背包的容量可以放下物品i
* 那么此时分两种情况:
* 1、不放物品i
* 2、放物品i
* 比较这两种情况下,哪种背包中物品的最大价值最大
*/
dp[i][j] = Math.max(dp[i - 1][j] , dp[i - 1][j - weight[i - 1]] + value[i - 1]); // i - 1 对应物品 i
}
}
}
// 打印dp数组
for(int[] arr : dp){
System.out.println(Arrays.toString(arr));
}
}
}
```
### python
无参数版
```python