写一些自己LeetCode的刷题过程及总结07
##leetcode上有2000+的题,不可能都刷完,我的刷题顺序是先分类型,然后再分难度,不断提升,当然过程中也参考了其他大神们的一些建议,光刷题收获不大,最重要的还是不断归纳总结,没事刷两道,坚持写总结其实也挺有意思的。##
##还在不断更新总结!##
##本文仅用来记录自己平时的学习收获##
##有朝一日我也能写出漂亮的代码!##
一、深度优先搜索(BFS)
深度优先搜索通常借助队列的先进先出的特性来实现,对于树形结构来说就是,先遍历完一层再遍历下一层;对于图形结构来说就是,先遍历一圈再遍历下一圈。对于树和图的遍历来说既可以用DFS也可以用BFS,个人感觉借助队列的BFS更好理解一些,而且也更容易来实现,因为它有固定的模板,只要根据题意完成细节部分的实现就好。所以这里就先对BFS的题目进行总结。在之前的博客栈与队列中我已经列出了部分BFS的题目,这里只是更详细一些。
1.1 leetcode部分栈与队列题目及代码
752.打开转盘锁
994.腐烂的橘子
815.公交路线
690.员工的重要性
130.被围绕的区域
133.克隆图
200.岛屿数量
207.课程表
210.课程表II
310.最小高度树
417.太平洋大西洋水流问题
542.01矩阵
1、752.打开转盘锁
//用队列进行BFS
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
unordered_set<string> set(deadends.begin(), deadends.end());
if (set.count("0000") == 1) return -1;
queue<string> que;
que.push("0000");
int count = 0;
while (!que.empty()) {
int len = que.size();
for (int i = 0; i < len; ++i) {
string str = que.front();
que.pop();
if (str == target) return count;
// 处理str周围的八个相邻结点
for (int j = 0; j < 4; ++j) {
//+1 、 -1
for (int k = -1; k < 2; k += 2) {
string cur = str;
cur[j] = (str[j] - '0' + 10 + k) % 10 + '0';
if (set.count(cur) != 1) {
set.insert(cur);
que.push(cur);
}
}
}
}
// 本层队列中元素处理完成,到达下一转动步数,步数加1
++count;
}
return -1;
}
};
2、994.腐烂的橘子
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
queue<pair<int, int>> que;
int freshNum = 0;
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid[0].size(); ++j) {
if (grid[i][j] == 1) ++freshNum;
else if (grid[i][j] == 2) que.push({i, j});
}
}
int minCount = 0;
vector<pair<int, int>> dict = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
while (!que.empty()) {
int len = que.size();
bool flag = false;
for (int i = 0; i < len; ++i) {
auto temp = que.front();
que.pop();
for (int j = 0; j < 4; ++j) {
int x = temp.first + dict[j].first;
int y = temp.second + dict[j].second;
if (x >=0 && x < grid.size() && y >= 0 && y < grid[0].size() && grid[x][y] == 1) {
grid[x][y] = 2;
--freshNum;
flag = true;
que.push({x, y});
}
}
}
if (flag) ++minCount;
}
if (freshNum != 0) return -1;
else return minCount;
}
};
3、815.公交路线
class Solution {
public:
int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {
if (source == target) return 0;
// 标记站点出现的线路
unordered_map<int, vector<int>> mp;
// 标记访问的线路
vector<bool> visited(routes.size(), false);
// 记录站点出现的线路
for (int i = 0; i < routes.size(); ++i) {
for (int j = 0; j < routes[i].size(); ++j) {
mp[routes[i][j]].push_back(i);
}
}
queue<int> que;
que.push(source);
int step = 0;
while (!que.empty()) {
++step;
int len = que.size();
for (int i = 0; i < len; ++i) {
int temp = que.front();
que.pop();
for (int m : mp[temp]) {
if (!visited[m]) {
for (int n = 0; n < routes[m].size(); ++n) {
if (routes[m][n] == target) return step;
que.push(routes[m][n]);
}
visited[m] = true;
}
}
}
}
return -1;
}
};
4、690.员工的重要性
class Solution {
public:
int getImportance(vector<Employee *> employees, int id) {
unordered_map<int, Employee *> mp;
for (auto &employee : employees) {
mp[employee->id] = employee;
}
int total = 0;
queue<int> que;
que.push(id);
while (!que.empty()) {
int curId = que.front();
que.pop();
Employee *employee = mp[curId];
total += employee->importance;
for (int subId : employee->subordinates) {
que.push(subId);
}
}
return total;
}
};
5、130.被围绕的区域
class Solution {
public:
void solve(vector<vector<char>>& board) {
int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
queue<pair<int, int>> que;
int m = board.size();
int n = board[0].size();
for (int i = 0; i < m; ++i) {
if (board[i][0] == 'O') {
que.push({i, 0});
}
if (board[i][n - 1] == 'O') {
que.push({i, n - 1});
}
}
for (int j = 0; j < n; ++j) {
if (board[0][j] == 'O') {
que.push({0, j});
}
if (board[m - 1][j] == 'O') {
que.push({m - 1, j});
}
}
while (!que.empty()) {
int x = que.front().first;
int y = que.front().second;
que.pop();
board[x][y] = 'A';
for (int k = 0; k < 4; ++k) {
int dx = x + dir[k][0];
int dy = y + dir[k][1];
if (dx < 0 || dx >= m || dy < 0 || dy >= n || board[dx][dy] != 'O') {
continue;
} else {
que.push({dx, dy});
}
}
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (board[i][j] == 'A') {
board[i][j] = 'O';
} else if (board[i][j] == 'O') {
board[i][j] = 'X';
}
}
}
}
};
6、133.克隆图
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/
class Solution {
public:
Node* cloneGraph(Node* node) {
if (node == nullptr) return node;
unordered_map<Node*, Node*> visited;
queue<Node*> q;
// 将题目给定的节点添加到队列
q.push(node);
// 克隆第一个节点并存储到哈希表中
visited[node] = new Node(node->val);
while (!q.empty()) {
// 取出队列的头节点
auto cur = q.front();
q.pop();
// 遍历该节点的邻居
for (auto neighbor : cur->neighbors) {
if (visited.find(neighbor) == visited.end()) {
// 如果没有被访问过,就克隆并存储在哈希表中
visited[neighbor] = new Node(neighbor->val);
// 将邻居节点加入队列中
q.push(neighbor);
}
// 更新当前节点的邻居列表
visited[cur]->neighbors.push_back(visited[neighbor]);
}
}
return visited[node];
}
};
7、200.岛屿数量
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
if (grid.size() == 0) return 0;
int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
int ret = 0;
int m = grid.size();
int n = grid[0].size();
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == '1') {
++ret;
queue<pair<int, int>> q;
q.push({i, j});
while (!q.empty()) {
int x = q.front().first;
int y = q.front().second;
q.pop();
for (int k = 0; k < 4; ++k) {
int dx = x + dir[k][0];
int dy = y + dir[k][1];
if (dx >= 0 && dx < m && dy >= 0 && dy < n && grid[dx][dy] == '1') {
q.push({dx, dy});
grid[dx][dy] = '0';
}
}
}
}
}
}
return ret;
}
};
8、207.课程表
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
//记录所有顶点的入度,未初始化的为0
vector<int> degrees(numCourses);
//邻接表
vector<vector<int>> adjacents(numCourses);
for (int i = 0; i < prerequisites.size(); ++i) {
//入顶点
++degrees[prerequisites[i][0]];
//出顶点
adjacents[prerequisites[i][1]].push_back(prerequisites[i][0]);
}
//零入度的顶点
queue<int> q;
int num = numCourses;
for (int i = 0; i < numCourses; ++i) {
if (degrees[i] == 0) {
//入度为0的先入队列
q.push(i);
--num;
}
}
while (!q.empty()) {
int temp = q.front();
q.pop();
for (int i = 0; i < adjacents[temp].size(); ++i) {
if (--degrees[adjacents[temp][i]] == 0) {
q.push(adjacents[temp][i]);
--num;
}
}
}
if (num == 0) return true;
else return false;
}
};
9、210.课程表II
//在上一道题的基础上略做修改即可
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> degrees(numCourses);
vector<vector<int>> adjacents(numCourses);
for (int i = 0; i < prerequisites.size(); ++i) {
++degrees[prerequisites[i][0]];
adjacents[prerequisites[i][1]].push_back(prerequisites[i][0]);
}
vector<int> ret;
queue<int> q;
for (int i = 0; i < numCourses; ++i) {
if (degrees[i] == 0) {
q.push(i);
}
}
while (!q.empty()) {
int temp = q.front();
q.pop();
ret.push_back(temp);
for (int i = 0; i < adjacents[temp].size(); ++i) {
if (--degrees[adjacents[temp][i]] == 0) {
q.push(adjacents[temp][i]);
}
}
}
if (ret.size() != numCourses) return {};
else return ret;
}
};
10、310.最小高度树
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
// case case(边界条件)
if (n == 1) return { 0 };
// step1: 构建带度的无向图。 度定义为与当前顶点相邻的顶点(边)的数量!
vector<vector<int>> g(n);
vector<int> degrees(n);
for (const auto& e : edges) {
++degrees[e[0]];
++degrees[e[1]];
g[e[0]].push_back(e[1]);
g[e[1]].push_back(e[0]);
}
// 把所有度为1的节点,即叶节点加入队列
queue<int> q;
for (int i = 0; i < n; ++i) {
if (degrees[i] == 1) {
q.push(i);
}
}
vector<int> ret;
while (!q.empty()) {
ret.clear();//这一步是核心
int len = q.size();
for (int i = 0; i < len; ++i) {
int cur = q.front();
q.pop();
ret.push_back(cur);
for (auto& c : g[cur]) {
if (--degrees[c] == 1) {
q.push(c);
}
}
}
}
return ret;
}
};
11、417.太平洋大西洋水流问题
class Solution {
private:
vector<vector<int>> ret;
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
public:
void bfs(vector<vector<int>>& heights, vector<vector<int>>& visited, int x, int y, int constrain, int inc) {
//x 和 y 表示初始进行BFS的起点,constrain表示用于判断节点是否访问过,inc 表示访问节点时的自增程度
queue<pair<int, int>> q;
q.push({x, y});
int m = heights.size();
int n = heights[0].size();
while (!q.empty()) {
int len = q.size();
for (int i = 0; i < len; ++i) {
auto temp = q.front();
q.pop();
for (int j = 0; j < 4; ++j) {
int dx = temp.first + dir[j][0];
int dy = temp.second + dir[j][1];
if (dx < 0 || dx >= m || dy < 0 || dy >= n || visited[dx][dy] > constrain || heights[temp.first][temp.second] > heights[dx][dy]) {
continue;
}
q.push({dx, dy});
visited[dx][dy] += inc;
}
}
}
}
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
int m = heights.size();
int n = heights[0].size();
vector<vector<int>> visited(m, vector<int> (n, 0));
//两个太平洋边界
for (int i = 0; i < n; ++i) {
if (visited[0][i] == 0) {
++visited[0][i];
bfs(heights, visited, 0, i, 0, 1);
}
}
for (int i = 0; i < m; ++i) {
if (visited[i][0] == 0) {
++visited[i][0];
bfs(heights, visited, i, 0, 0, 1);
}
}
//两个大西洋边界
for (int i = 0; i < n; ++i) {
if (visited[m - 1][i] <= 1) {
visited[m - 1][i] += 2;
bfs(heights, visited, m - 1, i, 1, 2);
}
}
for (int i = 0; i < m; ++i) {
if (visited[i][n - 1] <= 1) {
visited[i][n - 1] += 2;
bfs(heights, visited, i, n - 1, 1, 2);
}
}
//找到交界处
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (visited[i][j] == 3) {
ret.push_back({i, j});
}
}
}
return ret;
}
};
12、542.01矩阵
class Solution {
private:
int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int m = mat.size();
int n = mat[0].size();
vector<vector<int>> ret(m, vector<int> (n, 0));
vector<vector<int>> vis(m, vector<int> (n, 0));
queue<pair<int, int>> q;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (mat[i][j] == 0) {
q.push({i, j});
vis[i][j] = 1;
}
}
}
while (!q.empty()) {
auto pos = q.front();
q.pop();
int x = pos.first;
int y = pos.second;
for (int i = 0; i < 4; ++i) {
int dx = x + dir[i][0];
int dy = y + dir[i][1];
if (dx >= 0 && dx < m && dy >= 0 && dy < n && vis[dx][dy] != 1) {
ret[dx][dy] = ret[x][y] + 1;
q.push({dx, dy});
vis[dx][dy] = 1;
}
}
}
return ret;
}
};
1.2 总结
做了这些题目后也不难发现,BFS的解法其实是有一个模板的,只要在这个基础上根据题意对细节部分进行实现就好。