Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions problems/1002.查找常用字符.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

输入:words = ["bella","label","roller"]
输出:["e","l","l"]

示例 2:

输入:words = ["cool","lock","cook"]
Expand Down
30 changes: 15 additions & 15 deletions problems/图论深搜理论基础.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@

## dfs 与 bfs 区别

提到深度优先搜索(dfs),就不得不说和广度优先有什么区别(bfs)
提到深度优先搜索(dfs),就不得不说和广度优先搜索(bfs)有什么区别

先来了解dfs的过程,很多录友可能对dfs(深度优先搜索),bfs(广度优先搜索)分不清。

先给大家说一下两者大概的区别:

* dfs是可一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,在换方向(换方向的过程就涉及到了回溯)。
* dfs是可一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,再换方向(换方向的过程就涉及到了回溯)。
* bfs是先把本节点所连接的所有节点遍历一遍,走到下一个节点的时候,再把连接节点的所有节点遍历一遍,搜索方向更像是广度,四面八方的搜索过程。

当然以上讲的是,大体可以这么理解,接下来 我们详细讲解dfs,(bfs在用单独一篇文章详细讲解)
Expand Down Expand Up @@ -60,26 +60,26 @@

上图演示中,其实我并没有把 所有的 从节点1 到节点6的dfs(深度优先搜索)的过程都画出来,那样太冗余了,但 已经把dfs 关键的地方都涉及到了,关键就两点:

* 搜索方向,是认准一个方向搜,直到碰壁之后在换方向
* 搜索方向,是认准一个方向搜,直到碰壁之后再换方向
* 换方向是撤销原路径,改为节点链接的下一个路径,回溯的过程。

## 代码框架

正式因为dfs搜索可一个方向,并需要回溯,所以用递归的方式来实现是最方便的。
正是因为dfs搜索可一个方向,并需要回溯,所以用递归的方式来实现是最方便的。

很多录友对回溯很陌生,建议先看看码随想录,[回溯算法章节](https://programmercarl.com/回溯算法理论基础.html)。
很多录友对回溯很陌生,建议先看看代码随想录,[回溯算法章节](https://programmercarl.com/回溯算法理论基础.html)。

有递归的地方就有回溯,那么回溯在哪里呢?

就地递归函数的下面,例如如下代码:

```
```cpp
void dfs(参数) {
处理节点
dfs(图,选择的节点); // 递归
回溯,撤销处理结果
}
```
```

可以看到回溯操作就在递归函数的下面,递归和回溯是相辅相成的。

Expand All @@ -89,7 +89,7 @@ void dfs(参数) {

我们在回顾一下[回溯法](https://programmercarl.com/回溯算法理论基础.html)的代码框架:

```
```cpp
void backtracking(参数) {
if (终止条件) {
存放结果;
Expand All @@ -102,11 +102,11 @@ void backtracking(参数) {
}
}

```
```

回溯算法,其实就是dfs的过程,这里给出dfs的代码框架:

```
```cpp
void dfs(参数) {
if (终止条件) {
存放结果;
Expand Down Expand Up @@ -136,17 +136,17 @@ void dfs(参数) {

1. 确认递归函数,参数

```
```cpp
void dfs(参数)
```
```

通常我们递归的时候,我们递归搜索需要了解哪些参数,其实也可以在写递归函数的时候,发现需要什么参数,再去补充就可以。

一般情况,深搜需要 二维数组数组结构保存所有路径,需要一维数组保存单一路径,这种保存结果的数组,我们可以定义一个全局遍历,避免让我们的函数参数过多。

例如这样:

```
```cpp
vector<vector<int>> result; // 保存符合条件的所有路径
vector<int> path; // 起点到终点的路径
void dfs (图,目前搜索的节点)
Expand All @@ -158,7 +158,7 @@ void dfs (图,目前搜索的节点)

终止条件很重要,很多同学写dfs的时候,之所以容易死循环,栈溢出等等这些问题,都是因为终止条件没有想清楚。

```
```cpp
if (终止条件) {
存放结果;
return;
Expand All @@ -173,7 +173,7 @@ if (终止条件) {

一般这里就是一个for循环的操作,去遍历 目前搜索节点 所能到的所有节点。

```
```cpp
for (选择:本节点所连接的其他节点) {
处理节点;
dfs(图,选择的节点); // 递归
Expand Down
58 changes: 58 additions & 0 deletions problems/背包理论基础01背包-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down