Skip to content
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,32 @@
4. [单调栈:42.接雨水](./problems/0042.接雨水.md)
5. [单调栈:84.柱状图中最大的矩形](./problems/0084.柱状图中最大的矩形.md)

(持续更新中....)

## 图论

通知:开始更新图论内容,图论部分还没有其他语言版本,欢迎录友们提交PR,成为contributor

### 深搜广搜

* [图论:深度优先搜索理论基础](./problems/图论深搜理论基础.md)
* [图论:797.所有可能的路径](./problems/0797.所有可能的路径.md)
* [图论:广度优先搜索理论基础](./problems/图论广索理论基础.md)
* [图论:200.岛屿数量.深搜版](./problems/0200.岛屿数量.深搜版.md)
* [图论:200.岛屿数量.广搜版](./problems/0200.岛屿数量.广搜版.md)
* [图论:695.岛屿的最大面积](./problems/0695.岛屿的最大面积.md)
* [图论:1020.飞地的数量](./problems/1020.飞地的数量.md)
* [图论:130.被围绕的区域](./problems/0130.被围绕的区域.md)
* [图论:417.太平洋大西洋水流问题](./problems/0417.太平洋大西洋水流问题.md)
* [图论:827.最大人工岛](./problems/0827.最大人工岛.md)
* [图论:127.单词接龙](./problems/0127.单词接龙.md)
* [图论:841.钥匙和房间](./problems/0841.钥匙和房间.md)
* [图论:463.岛屿的周长](./problems/0463.岛屿的周长.md)

### 并查集

(持续更新中....)


## 十大排序

## 数论
Expand Down Expand Up @@ -492,7 +514,7 @@

大家好,我是程序员Carl,哈工大师兄,《代码随想录》作者,先后在腾讯和百度从事后端技术研发,CSDN博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。

加入「代码随想录」刷题小分队(微信群),可以扫下方二维码加我微信
加入「代码随想录」刷题小分队(微信群),可以扫下方二维码,加代码随想录客服微信

如果是已工作,备注:姓名-城市-岗位-组队刷题。如果学生,备注:姓名-学校-年级-组队刷题。**备注没有自我介绍不通过哦**

Expand Down
11 changes: 8 additions & 3 deletions problems/0053.最大子序和(动态规划).md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
* 输入: [-2,1,-3,4,-1,2,1,-5,4]
* 输出: 6
* 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

## 算法公开课

**《代码随想录》算法视频公开课:[看起来复杂,其实是简单动态规划 | LeetCode:53.最大子序和](https://www.bilibili.com/video/BV19V4y1F7b5),相信结合视频再看本篇题解,更有助于大家对本题的理解**。


## 思路

Expand Down
5 changes: 3 additions & 2 deletions problems/0115.不同的子序列.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@

提示:

0 <= s.length, t.length <= 1000
s 和 t 由英文字母组成
* 0 <= s.length, t.length <= 1000
* s 和 t 由英文字母组成


## 思路

Expand Down
5 changes: 5 additions & 0 deletions problems/0300.最长上升子序列.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
* 1 <= nums.length <= 2500
* -10^4 <= nums[i] <= 104

## 算法公开课

**《代码随想录》算法视频公开课:[动态规划之子序列问题,元素不连续!| LeetCode:300.最长递增子序列](https://www.bilibili.com/video/BV1ng411J7xP),相信结合视频再看本篇题解,更有助于大家对本题的理解**。


## 思路

首先通过本题大家要明确什么是子序列,“子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序”。
Expand Down
12 changes: 8 additions & 4 deletions problems/0392.判断子序列.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

示例 1:
输入:s = "abc", t = "ahbgdc"
输出:true
* 输入:s = "abc", t = "ahbgdc"
* 输出:true

示例 2:
输入:s = "axc", t = "ahbgdc"
输出:false
* 输入:s = "axc", t = "ahbgdc"
* 输出:false

提示:

Expand All @@ -28,6 +28,10 @@

两个字符串都只由小写字符组成。

# 算法公开课

**《代码随想录》算法视频公开课:[动态规划,用相似思路解决复杂问题 | LeetCode:392.判断子序列](https://www.bilibili.com/video/BV1tv4y1B7ym/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。


## 思路

Expand Down
27 changes: 27 additions & 0 deletions problems/0474.一和零.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,33 @@ object Solution {
}
```

### Rust

```rust
impl Solution {
pub fn find_max_form(strs: Vec<String>, m: i32, n: i32) -> i32 {
let (m, n) = (m as usize, n as usize);
let mut dp = vec![vec![0; n + 1]; m + 1];
for s in strs {
let (mut one_num, mut zero_num) = (0, 0);
for c in s.chars() {
match c {
'0' => zero_num += 1,
'1' => one_num += 1,
_ => (),
}
}
for i in (zero_num..=m).rev() {
for j in (one_num..=n).rev() {
dp[i][j] = dp[i][j].max(dp[i - zero_num][j - one_num] + 1);
}
}
}
dp[m][n]
}
}
```

<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
Expand Down
24 changes: 24 additions & 0 deletions problems/0491.递增子序列.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,30 @@ public:


### Java
```Java
//using set, aligned with the unimproved method
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backTracking(nums, 0);
return result;
}
private void backTracking(int[] nums, int startIndex){
if(path.size() >= 2)
result.add(new ArrayList<>(path));
HashSet<Integer> hs = new HashSet<>();
for(int i = startIndex; i < nums.length; i++){
if(!path.isEmpty() && path.get(path.size() -1 ) > nums[i] || hs.contains(nums[i]))
continue;
hs.add(nums[i]);
path.add(nums[i]);
backTracking(nums, i + 1);
path.remove(path.size() - 1);
}
}
}
```

```java
class Solution {
Expand Down
4 changes: 4 additions & 0 deletions problems/0674.最长连续递增序列.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
* 0 <= nums.length <= 10^4
* -10^9 <= nums[i] <= 10^9

## 算法公开课

**《代码随想录》算法视频公开课:[动态规划之子序列问题,重点在于连续!| LeetCode:674.最长连续递增序列](https://www.bilibili.com/video/BV1bD4y1778v),相信结合视频再看本篇题解,更有助于大家对本题的理解**。


## 思路

Expand Down
70 changes: 43 additions & 27 deletions problems/0684.冗余连接.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
这里整理出我的并查集模板如下:

```CPP
int n = 1005; // 节点数量3 到 1000
int father[1005];
int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好
vector<int> father = vector<int> (n, 0); // C++里的一种数组结构

// 并查集初始化
void init() {
Expand All @@ -50,40 +50,58 @@ void init() {
}
// 并查集里寻根的过程
int find(int u) {
return u == father[u] ? u : father[u] = find(father[u]);
}
// 将v->u 这条边加入并查集
void join(int u, int v) {
u = find(u);
v = find(v);
if (u == v) return ;
father[v] = u;
return u == father[u] ? u : father[u] = find(father[u]); // 路径压缩
}

// 判断 u 和 v是否找到同一个根
bool same(int u, int v) {
bool isSame(int u, int v) {
u = find(u);
v = find(v);
return u == v;
}

// 将v->u 这条边加入并查集
void join(int u, int v) {
u = find(u); // 寻找u的根
v = find(v); // 寻找v的根
if (u == v) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
father[v] = u;
}

```

以上模板汇总,只要修改 n 和father数组的大小就可以了
以上模板 只要修改 n 就可以了,本题 节点数量不会超过1000

并查集主要有三个功能。

1. 寻找根节点,函数:find(int u),也就是判断这个节点的祖先节点是哪个
2. 将两个节点接入到同一个集合,函数:join(int u, int v),将两个节点连在同一个根节点上
3. 判断两个节点是否在同一个集合,函数:same(int u, int v),就是判断两个节点是不是同一个根节点
3. 判断两个节点是否在同一个集合,函数:isSame(int u, int v),就是判断两个节点是不是同一个根节点

简单介绍并查集之后,我们再来看一下这道题目。

题目说是无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树。
题目说是无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点)

如果有多个答案,则返回二维数组中最后出现的边。

那么我们就可以从前向后遍历每一条边,边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
那么我们就可以从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。

如图所示:

![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230604104720.png)

节点A 和节点 B 不在同一个集合,那么就可以将两个 节点连在一起。

如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,如果再加入这条边一定就出现环了。

(如果题目中说:如果有多个答案,则返回二维数组中最前出现的边。 那我们就要 从后向前遍历每一条边了)

如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。

如图所示:

![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230604104330.png)

已经判断 节点A 和 节点B 在在同一个集合(同一个根),如果将 节点A 和 节点B 连在一起就一定会出现环。

这个思路清晰之后,代码就很好写了。

Expand All @@ -93,7 +111,7 @@ bool same(int u, int v) {
class Solution {
private:
int n = 1005; // 节点数量3 到 1000
int father[1005];
vector<int> father = vector<int> (n, 0); // C++里的一种数组结构

// 并查集初始化
void init() {
Expand All @@ -105,24 +123,22 @@ private:
int find(int u) {
return u == father[u] ? u : father[u] = find(father[u]);
}
// 将v->u 这条边加入并查集
void join(int u, int v) {
u = find(u);
v = find(v);
if (u == v) return ;
father[v] = u;
}
// 判断 u 和 v是否找到同一个根,本题用不上
bool same(int u, int v) {
// 判断 u 和 v是否找到同一个根
bool isSame(int u, int v) {
u = find(u);
v = find(v);
return u == v;
}
// 将v->u 这条边加入并查集
void join(int u, int v) {
if (isSame(u, v)) return ;
father[v] = u;
}
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
init();
for (int i = 0; i < edges.size(); i++) {
if (same(edges[i][0], edges[i][1])) return edges[i];
if (isSame(edges[i][0], edges[i][1])) return edges[i];
else join(edges[i][0], edges[i][1]);
}
return {};
Expand Down
25 changes: 22 additions & 3 deletions problems/0685.冗余连接II.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,34 @@

且只有一个节点入度为2,为什么不看出度呢,出度没有意义,一棵树中随便一个父节点就有多个出度。


第三种情况是没有入度为2的点,那么图中一定出现了有向环(**注意这里强调是有向环!**)

如图:

<img src='https://code-thinking.cdn.bcebos.com/pics/685.冗余连接II2.png' width=600> </img></div>


首先先计算节点的入度,代码如下:
首先先计算节点的入度,这里不少录友在计算入度的时候就搞蒙了,分不清 edges[i][j] 表示的都是什么。

例如题目示例一给的是:edges = [[1,2],[1,3],[2,3]]

那大家很自然就想 对应二维数组的数值是: edges[1][2] ,edges[1][3],edges[2][3],但又想不出来 edges[1][2] 数值又是什么呢? 越想约懵。

其实 edges = [[1,2],[1,3],[2,3]],表示的是

edges[0][0] = 1,edges[0][1] = 2,

edges[1][0] = 1,edges[1][1] = 3,

edges[2][0] = 2,edges[2][1] = 3,

二维数组大家都学过,但是往往和图结合在一起的时候,就非常容易搞混,哪里是数组,哪里是下标了。

搞清楚之后,我们如何统计入度呢?

即 edges[i][1] 表示的节点都是 箭头指向的节点,即这个几点有一个入度! (如果想统计出度,那么就是 edges[i][0])。

所以,统计入度的代码如下:

```cpp
int inDegree[N] = {0}; // 记录节点入度
Expand Down Expand Up @@ -94,7 +113,7 @@ if (vec.size() > 0) {
vector<int> getRemoveEdge(const vector<vector<int>>& edges)
```

此时 大家应该知道了,我们要实现两个最为关键的函数:
大家应该知道了,我们要实现两个最为关键的函数:

* `isTreeAfterRemoveEdge()` 判断删一个边之后是不是树了
* `getRemoveEdge` 确定图中一定有了有向环,那么要找到需要删除的那条边
Expand Down
5 changes: 5 additions & 0 deletions problems/0718.最长重复子数组.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
* 1 <= len(A), len(B) <= 1000
* 0 <= A[i], B[i] < 100

## 算法公开课

**《代码随想录》算法视频公开课:[动态规划之子序列问题,想清楚DP数组的定义 | LeetCode:718.最长重复子数组](https://www.bilibili.com/video/BV178411H7hV),相信结合视频再看本篇题解,更有助于大家对本题的理解**。



## 思路

Expand Down
4 changes: 2 additions & 2 deletions problems/0797.所有可能的路径.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public:

## 其他语言版本

## Java
Java

```Java
// 深度优先遍历
Expand Down Expand Up @@ -190,7 +190,7 @@ class Solution {
}
```

## Python
Python
```python
class Solution:
def __init__(self):
Expand Down
Loading