算法 - 回溯 / DFS / BFS

文章目录

  • [🍺 回溯](#🍺 回溯)
    • [🍻 子集](#🍻 子集)
      • [🥂 78. 子集 [无重数组] [子集] (回溯)](#🥂 78. 子集 [无重数组] [子集] (回溯))
      • [🥂 90. 子集Ⅱ [有重数组] [子集] (回溯)](#🥂 90. 子集Ⅱ [有重数组] [子集] (回溯))
    • [🍻 组合](#🍻 组合)
      • [🥂 39. 组合总和 [无重数组] [组合] (回溯)](#🥂 39. 组合总和 [无重数组] [组合] (回溯))
      • [🥂 40. 组合总和Ⅱ [有重数组] [组合] (回溯)](#🥂 40. 组合总和Ⅱ [有重数组] [组合] (回溯))
      • [🥂 77. 组合 [无重数组] [组合] (回溯)](#🥂 77. 组合 [无重数组] [组合] (回溯))
      • [🥂 698. 划分为K个相等的子集 [有重数组] [组合] (回溯)](#🥂 698. 划分为K个相等的子集 [有重数组] [组合] (回溯))
    • [🍻 排列](#🍻 排列)
      • [🥂 22. 括号生成 [字符串数组] [括号] (回溯)](#🥂 22. 括号生成 [字符串数组] [括号] (回溯))
      • [🥂 37. 解数独 [矩阵] [数独] (回溯)](#🥂 37. 解数独 [矩阵] [数独] (回溯))
      • [🥂 46. 全排列 [无重数组] [排列] (回溯)](#🥂 46. 全排列 [无重数组] [排列] (回溯))
      • [🥂 47. 全排列Ⅱ [有重数组] [排列] (回溯)](#🥂 47. 全排列Ⅱ [有重数组] [排列] (回溯))
      • [🥂 51. N皇后 [矩阵] [排列] (回溯)](#🥂 51. N皇后 [矩阵] [排列] (回溯))
      • [🥂 52. N皇后Ⅱ [矩阵] [排列] (回溯)](#🥂 52. N皇后Ⅱ [矩阵] [排列] (回溯))
  • [🍺 DFS](#🍺 DFS)
    • [🍻 岛屿问题](#🍻 岛屿问题)
      • [🥂 200. 岛屿数量 [矩阵] [岛屿] (DFS)](#🥂 200. 岛屿数量 [矩阵] [岛屿] (DFS))
      • [🥂 694. 不同岛屿的数量 [矩阵] [岛屿] (DFS) (序列化)](#🥂 694. 不同岛屿的数量 [矩阵] [岛屿] (DFS) (序列化))
      • [🥂 695. 岛屿的最大面积 [矩阵] [岛屿] (DFS)](#🥂 695. 岛屿的最大面积 [矩阵] [岛屿] (DFS))
      • [🥂 1020. 飞地的数量 [矩阵] [岛屿] (DFS)](#🥂 1020. 飞地的数量 [矩阵] [岛屿] (DFS))
      • [🥂 1254. 统计封闭岛屿的数目 [矩阵] [岛屿] (DFS)](#🥂 1254. 统计封闭岛屿的数目 [矩阵] [岛屿] (DFS))
      • [🥂 1905. 统计子岛屿 [矩阵] [岛屿] (DFS)](#🥂 1905. 统计子岛屿 [矩阵] [岛屿] (DFS))
  • [🍺 BFS](#🍺 BFS)
    • [🍻 最小距离](#🍻 最小距离)
      • [🥂 111. 二叉树的最小深度 [二叉树] [最小距离] (BFS)](#🥂 111. 二叉树的最小深度 [二叉树] [最小距离] (BFS))
      • [🥂 752. 打开转盘锁 [字符串数组] [最小距离] (BFS)](#🥂 752. 打开转盘锁 [字符串数组] [最小距离] (BFS))
    • [🍻 层序遍历](#🍻 层序遍历)
      • [🥂 102. 二叉树的层序遍历 [二叉树] [遍历] (BFS)](#🥂 102. 二叉树的层序遍历 [二叉树] [遍历] (BFS))

🍺 回溯

🍻 子集

🥂 78. 子集 [无重数组] [子集] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<int>> res;    // 无重数组的子集
    vector<int> track;          // 当前子集元素
    int n;                      // 元素个数
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        n = nums.size();
        backtrack(nums, 0);
        return res;
    }
    // 回溯算法
    void backtrack(vector<int>& nums, int start) {
        // 终止条件, 回溯每一步都是一种情况
        res.push_back(track);
        // 选择列表, 从当前位置开始, 向后选择
        for (int i = start; i < n; ++i) {
            // 做选择, 更新选择列表
            track.push_back(nums[i]);
            // 下一层选择
            backtrack(nums, i + 1);
            // 撤销选择, 更新选择列表
            track.pop_back();
        }
    }
};

🥂 90. 子集Ⅱ [有重数组] [子集] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<int>> res;    // 存放符合条件的子集
    vector<int> track;          // 当前遍历的元素
    int n;                      // 数组长度
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        n = nums.size();
        sort(nums.begin(), nums.end()); // 先给有重数组排序
        backtrack(nums, 0);
        return res;
    }
    // 回溯算法
    void backtrack(vector<int>& nums, int start) {
        // 结束条件, 剪枝后不会出现重复的情况
        res.push_back(track);
        // 选择列表, 从 start 向后逐个选择
        for (int i = start; i < n; ++i) {
            // 相邻分支都一样, 则剪枝
            if (i > start && nums[i] == nums[i - 1]) continue;
            // 做选择, 更新选择列表
            track.push_back(nums[i]);
            // 下一层选择
            backtrack(nums, i + 1);
            // 撤销选择, 更新选择列表
            track.pop_back();
        }
    }
};

🍻 组合

🥂 39. 组合总和 [无重数组] [组合] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<int>> res;    // 满足条件的组合
    vector<int> track;          // 当前遍历的元素
    int n;                      // 元素个数
    int target, cur = 0;        // 目标值, 当前值
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        n = candidates.size();
        this->target = target;
        backtrack(candidates, 0);
        return res;
    }
    // 回溯算法
    void backtrack(vector<int>& nums, int start) {
        // 终止条件
        if (cur == target) {
            res.push_back(track);
            return;
        }
        if (cur > target) return;
        // 选择列表, 从 start 到 end 依次遍历
        for (int i = start; i < n; ++i) {
            // 做选择
            track.push_back(nums[i]);
            cur += nums[i];
            // 下一层选择, 因为元素可复选, 那么需要从 i 继续开始
            backtrack(nums, i);
            // 撤消选择
            track.pop_back();
            cur -= nums[i];
        }
    }
};

🥂 40. 组合总和Ⅱ [有重数组] [组合] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<int>> res;    // 存放符合条件的组合
    vector<int> track;          // 当前遍历的元素
    int n;                      // 数组的长度
    int target, cur = 0;        // 目标和, 当前和
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        n = candidates.size();
        this->target = target;
        sort(candidates.begin(), candidates.end());
        backtrack(candidates, 0);
        return res;
    }
    // 回溯算法
    void backtrack(vector<int>& nums, int start) {
        // 终止条件
        if (cur == target) {
            res.push_back(track);
            return;
        }
        if (cur > target) return;
        // 选择列表, 从 start 往右开始选择
        for (int i = start; i < n; ++i) {
            // 相邻元素相同, 剪枝
            if (i > start && nums[i] == nums[i - 1]) continue;
            // 做选择
            track.push_back(nums[i]);
            cur += nums[i];
            // 下一层
            backtrack(nums, i + 1);
            // 撤销选择
            track.pop_back();
            cur -= nums[i];
        }
    }
};

🥂 77. 组合 [无重数组] [组合] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<int>> res;    // 符合条件的组合
    vector<int> track;          // 当前遍历的元素
    int n, k;                   // 元素个数, 限制个数
public:
    vector<vector<int>> combine(int n, int k) {
        this->n = n, this->k = k;
        backtrack(1);
        return res;
    }
    // 回溯算法
    void backtrack(int start) {
        // 结束条件
        if (track.size() == k) {
            res.push_back(track);
            return;
        }
        // 选择列表, 从 start 往后选择
        for (int i = start; i <= n; ++i) {
            // 做选择, 更新选择列表
            track.push_back(i);
            // 下一层选择
            backtrack(i + 1);
            // 撤销选择, 更新选择列表
            track.pop_back();
        }
    }
};

🥂 698. 划分为K个相等的子集 [有重数组] [组合] (回溯)

cpp 复制代码
class Solution {
private:
    int n, k;               // 元素长度, 桶长度
    int target, sum = 0;    // 每个桶凑的目标值, 总和
    vector<int> track;      // K 个桶子
    bool res = false;       // 是否可行
public:
    bool canPartitionKSubsets(vector<int>& nums, int k) {
        n = nums.size(), this->k = k;
        for (int i = 0; i < n; ++i) {
            sum += nums[i];
        }
        if (sum % k != 0) return false;
        target = sum / k;
        track = vector<int>(k);
        sort(nums.begin(), nums.end(), [](const int& a, const int& b) {
            return a > b;
        });
        return backtrack(nums, 0);
    }
    // 回溯算法, idx 代表已经放入的球
    bool backtrack(vector<int>& nums, int idx) {
        // 结束条件
        if (idx == n) {
            return true;
        }
        // 选择列表, 从 0 到 k 桶开始选择, 放入 idx 球
        for (int i = 0; i < k; ++i) {
            // 剪枝, 放入球后值大于 target, 选择下一桶
            if (track[i] + nums[idx] > target) continue;
            if (i > 0 && track[i] == track[i - 1]) continue;
            // 做选择
            track[i] += nums[idx];
            // 下一层选择, 下一层没问题, 同时当前球没问题, 返回 true
            if (backtrack(nums, idx + 1)) {
                return true;
            }
            // 撤消选择
            track[i] -= nums[idx];
        }
        // k 个桶都不满足
        return false;
    }
};

🍻 排列

🥂 22. 括号生成 [字符串数组] [括号] (回溯)

cpp 复制代码
class Solution {
private:
    vector<string> res;     // 存放符合的组合
    string track;           // 当前的遍历括号
public:
    vector<string> generateParenthesis(int n) {
        backtrack(n, n);
        return res;
    }
    // 回溯算法
    void backtrack(int left, int right) {
        // 如果左括号剩下的数量小于右括号, 不合法
        if (left > right) return;
        // 括号数小于 0, 不合法
        if (left < 0 || right < 0) return;
        // 括号用完了, 找到一种合法的
        if (left == 0 && right == 0) {
            res.push_back(track);
            return;
        }
        // 选择列表, 左括号, 右括号都试试
        // 做选择
        track.push_back('(');
        // 下一层
        backtrack(left - 1, right);
        // 撤销选择
        track.pop_back();
        // 做选择
        track.push_back(')');
        // 下一层
        backtrack(left, right - 1);
        // 撤销选择
        track.pop_back();
    }
};

🥂 37. 解数独 [矩阵] [数独] (回溯)

cpp 复制代码
class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtrack(board, 0, 0);
    }
    // 回溯算法
    bool backtrack(vector<vector<char>>& board, int i, int j) {
        // 终止条件
        if (i == 9) return true;
        // 一行一行的填
        if (j == 9) {
            return backtrack(board, i + 1, 0);
        }
        // 如果是填好的数字, 不用管
        if (board[i][j] != '.') {
            return backtrack(board, i, j + 1);
        }
        // 选择列表, 开始从 1 到 9 填入
        for (char ch = '1'; ch <= '9'; ++ch) {
            // 看数字是否有效
            if (!isValid(board, i, j, ch)) continue;
            // 做选择
            board[i][j] = ch;
            // 下一层选择
            if (backtrack(board, i, j + 1)) {
                return true;
            };
            // 撤销选择
            board[i][j] = '.';
        }
        // 没有找到可行解
        return false;
    }
    // 判断填的地方是否有效
    bool isValid(vector<vector<char>>& board, int row, int col, char val) {
        for (int i = 0; i < 9; ++i) {
            // 判断行是否存在重复
            if (board[row][i] == val) return false;
            // 判断列是否存在重复
            if (board[i][col] == val) return false;
            // 判断 3X3 是否重复
            if (board[row / 3 * 3 + i / 3][col / 3 * 3 + i % 3] == val) return false; 
        }
        return true;
    }
};

🥂 46. 全排列 [无重数组] [排列] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<int>> res;    // 存放最终的排列组合
    vector<int> track;          // 存放当前路径上的节点
    vector<int> used;           // 选择列表, 记录第 i 个节点是否被选择过
    int n;                      // 节点个数
public:
    vector<vector<int>> permute(vector<int>& nums) {
        n = nums.size();
        used = vector<int>(n);  // 选择列表初始化
        backtrack(nums);
        return res;
    }
    // 回溯算法
    void backtrack(vector<int>& nums) {
        // 结束条件
        if (track.size() == n) {
            res.push_back(track);
            return;
        }
        // 选择列表, 一个个开始选择
        for (int i = 0; i < n; ++i) {
            // 如果第 i 个数已经被使用过, 则跳过
            if (used[i] == 1) continue;     
            // 做选择, 更新选择列表
            used[i] = 1;
            track.push_back(nums[i]);
            // 下一层选择
            backtrack(nums);
            // 撤消选择, 更新选择列表
            used[i] = 0;
            track.pop_back();
        }
    }
};

🥂 47. 全排列Ⅱ [有重数组] [排列] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<int>> res;    // 存放符合排列
    vector<int> track;          // 当前遍历的元素
    vector<int> used;           // 第 i 个元素有无被使用过
    int n;                      // 元素个数
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        n = nums.size();
        sort(nums.begin(), nums.end());
        used = vector<int>(n);
        backtrack(nums);
        return res;
    }

    // 回溯算法
    void backtrack(vector<int>& nums) {
        // 终止条件
        if (track.size() == n) {
            res.push_back(track);
            return;
        }
        // 选择列表, 从 0 到 end 依次选择
        for (int i = 0; i < n; ++i) {
            // 判断有无被选过
            if (used[i]) continue;
            // 判断是否分支重复, 剪枝
            // 确保相同元素中 i-1 一定比 i 先使用
            if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue;
            // 做选择
            track.push_back(nums[i]);
            used[i] = 1;
            // 下一层选择
            backtrack(nums);
            // 撤消选择
            track.pop_back();
            used[i] = 0;
        }
    }
};

🥂 51. N皇后 [矩阵] [排列] (回溯)

cpp 复制代码
class Solution {
private:
    vector<vector<string>> res; // 存放符合的摆放方案
    vector<string> track;       // 初始化棋盘
    int n;                      // 棋盘边长
public:
    vector<vector<string>> solveNQueens(int n) {
        this->n = n;
        track = vector<string>(n, string(n, '.'));
        backtrack(0);
        return res;
    }
    // 回溯算法
    void backtrack(int row) {
        // 结束条件
        if (row == n) {
            res.push_back(track);
            return;
        }
        // 选择列表, 从左到右选择一行
        for (int col = 0; col < n; ++col) {
            // 判断是否可以选择
            if (!isValid(row, col)) continue;
            // 做选择, 更新选择列表
            track[row][col] = 'Q';
            // 下一层选择
            backtrack(row + 1);
            // 撤销选择, 更新选择列表
            track[row][col] = '.';
        }
    }
    // 判断棋盘摆放的位置是否有效
    bool isValid(int row, int col) {
        int n = track.size();
        // 列满足
        for (int i = row - 1; i >= 0; --i) {
            if (track[i][col] == 'Q') return false;
        }
        // 右上斜向满足
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; --i, ++j) {
            if (track[i][j] == 'Q') return false;
        }
        // 左上斜向满足
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i, --j) {
            if (track[i][j] == 'Q') return false;
        }
        return true;
    }
};

🥂 52. N皇后Ⅱ [矩阵] [排列] (回溯)

cpp 复制代码
class Solution {
private:
    int res = 0;                // 符合的摆放方案数量
    vector<string> track;       // 初始化棋盘
    int n;                      // 棋盘边长
public:
    int totalNQueens(int n) {
        this->n = n;
        track = vector<string>(n, string(n, '.'));
        backtrack(0);
        return res;
    }
    // 回溯算法
    void backtrack(int row) {
        // 结束条件
        if (row == n) {
            res++;
            return;
        }
        // 选择列表, 从左到右选择一行
        for (int col = 0; col < n; ++col) {
            // 判断是否可以选择
            if (!isValid(row, col)) continue;
            // 做选择, 更新选择列表
            track[row][col] = 'Q';
            // 下一层选择
            backtrack(row + 1);
            // 撤销选择, 更新选择列表
            track[row][col] = '.';
        }
    }
    // 判断棋盘摆放的位置是否有效
    bool isValid(int row, int col) {
        int n = track.size();
        // 列满足
        for (int i = row - 1; i >= 0; --i) {
            if (track[i][col] == 'Q') return false;
        }
        // 右上斜向满足
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; --i, ++j) {
            if (track[i][j] == 'Q') return false;
        }
        // 左上斜向满足
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i, --j) {
            if (track[i][j] == 'Q') return false;
        }
        return true;
    }
};

🍺 DFS

🍻 岛屿问题

🥂 200. 岛屿数量 [矩阵] [岛屿] (DFS)

cpp 复制代码
class Solution {
private:
    int m, n;               // 地图的宽高
    int res;                // 岛屿数量
    vector<vector<int>> dirts = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};     // 方向
public:
    int numIslands(vector<vector<char>>& grid) {
        m = grid.size(), n = grid[0].size();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == '1') {
                    DFS(grid, i, j);
                    res++;
                }
            }
        }
        return res;
    }
    // DFS
    void DFS(vector<vector<char>>& grid, int i, int j) {
        if (i < 0 || i >= m || j < 0 || j >= n) return;
        if (grid[i][j] == '0') return;
        // 将已遍历岛屿沉默
        grid[i][j] = '0';
        // 探寻四周的元素
        for (auto& dirt : dirts) {
            DFS(grid, i + dirt[0], j + dirt[1]);
        }
    }
};

🥂 694. 不同岛屿的数量 [矩阵] [岛屿] (DFS) (序列化)

cpp 复制代码
class Solution {
private:
    int m, n;                       // 地图的宽高
    int res = 0;                    // 不同岛屿的数量
    string track;              		// 序列化字符串路径
    vector<vector<int>> dirts = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};     // 方向
    unordered_set<string> uset;     // 记录进入岛屿的序列化字符串  
public:
    int numDistinctIslands(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    track = "";
                    DFS(grid, i, j, 0);
                    uset.insert(track);
                }
            }
        }
        return uset.size();
    }
    // DFS 
    void DFS(vector<vector<int>>& grid, int i, int j, int idx) {
        if (i < 0 || i >= m || j < 0 || j >= n) return;
        if (grid[i][j] == 0) return;
        // 将陆地淹没
        grid[i][j] = 0;
        // 进入岛屿, 并序列化路径
        track += to_string(idx) + ",";
        // 向四周扩散
        for (int d_idx = 0; d_idx < dirts.size(); d_idx++) {
            DFS(grid, i + dirts[d_idx][0], j + dirts[d_idx][1], d_idx);
        }
        // 退出岛屿, 并序列化路径
        track += to_string(-idx) + ",";
    }
};

🥂 695. 岛屿的最大面积 [矩阵] [岛屿] (DFS)

cpp 复制代码
class Solution {
private:
    int m, n;                   // 地图的面积
    int res = 0;           // 岛屿的最大面积, 当前面积
    vector<vector<int>> dirts = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};     // 方向
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 1) {
                    res = max(res, DFS(grid, i, j));
                }
            }
        }
        return res;
    }
    // DFS
    int DFS(vector<vector<int>>& grid, int i, int j) {
        // 越界或海水
        if (i < 0 || i >= m || j < 0 || j >= n) return 0;
        if (grid[i][j] == 0) return 0;
        int cur = 1;
        // 将陆地淹没
        grid[i][j] = 0;
        // 向四周扩散
        for (auto& dirt : dirts) {
            cur += DFS(grid, i + dirt[0], j + dirt[1]);
        }
        return cur;
    }
};

🥂 1020. 飞地的数量 [矩阵] [岛屿] (DFS)

cpp 复制代码
class Solution {
private:
    int m, n;           // 地图大小
    int res = 0;        // 飞地大小
    bool iscount;       // 是否开始统计陆地
    vector<vector<int>> dirts = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};     // 方向
public:
    int numEnclaves(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        // 先把沿海的岛给阉淹了
        for (int i = 0; i < m; ++i) {
            DFS(grid, i, 0);
            DFS(grid, i, n - 1);
        }
        for (int j = 0; j < n; ++j) {
            DFS(grid, 0, j);
            DFS(grid, m - 1, j);
        }
        // 统计下中间还剩多少飞岛
        iscount = true;
        for (int i = 1; i < m - 1; ++i) {
            for (int j = 1; j < n - 1; ++j) {
                if (grid[i][j] == 1) {
                    DFS(grid, i, j);
                }
            }
        }
        return res;
    }
    // DFS
    void DFS(vector<vector<int>>& grid, int i, int j) {
        if (i < 0 || i >= m || j < 0 || j >= n) return;
        if (grid[i][j] == 0) return;
        // 将陆地淹没
        grid[i][j] = 0;
        if (iscount) res++;
        // 向四周扩散
        for (auto& dirt : dirts) {
            DFS(grid, i + dirt[0], j + dirt[1]);
        }
    }
};

🥂 1254. 统计封闭岛屿的数目 [矩阵] [岛屿] (DFS)

cpp 复制代码
class Solution {
private:
    int m, n;                       // 地图的宽高
    int res = 0;                        // 岛屿数量
    vector<vector<int>> dirts = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};     // 方向
public:
    int closedIsland(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        // 先把沿海的岛给阉淹了
        for (int i = 0; i < m; ++i) {
            DFS(grid, i, 0);
            DFS(grid, i, n - 1);
        }
        for (int j = 0; j < n; ++j) {
            DFS(grid, 0, j);
            DFS(grid, m - 1, j);
        }
        // 统计下中间还剩多少岛
        for (int i = 1; i < m - 1; ++i) {
            for (int j = 1; j < n - 1; ++j) {
                if (grid[i][j] == 0) {
                    DFS(grid, i, j);
                    res++;
                }
            }
        }
        return res;
    }
    // DFS
    void DFS(vector<vector<int>>& grid, int i, int j) {
        if (i < 0 || i >= m || j < 0 || j >= n) return;
        if (grid[i][j] == 1) return;
        // 将陆地淹没
        grid[i][j] = 1;
        // 向四周扩散
        for (auto& dirt : dirts) {
            DFS(grid, i + dirt[0], j + dirt[1]);
        }
    }
};

🥂 1905. 统计子岛屿 [矩阵] [岛屿] (DFS)

cpp 复制代码
class Solution {
private:
    int m, n;                       // 地图的宽高
    int res = 0;                    // 子岛屿数量
    vector<vector<int>> dirts = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};     // 方向
public:
    int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
        m = grid1.size(), n = grid1[0].size();
        // 先找出不是子岛屿的岛
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid1[i][j] == 0 && grid2[i][j] == 1) {
                    DFS(grid2, i, j);
                }
            }
        }
        // 统计剩下的岛屿
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid2[i][j] == 1) {
                    DFS(grid2, i, j);
                    res++;
                }
            }
        }
        return res;
    }
    // DFS
    void DFS(vector<vector<int>>& grid, int i, int j) {
        if (i < 0 || i >= m || j < 0 || j >= n) return;
        if (grid[i][j] == 0) return;
        // 将陆地淹没
        grid[i][j] = 0;
        // 向四周扩散
        for (auto& dirt : dirts) {
            DFS(grid, i + dirt[0], j + dirt[1]);
        }
    }
};

🍺 BFS

🍻 最小距离

🥂 111. 二叉树的最小深度 [二叉树] [最小距离] (BFS)

cpp 复制代码
class Solution {
private:
    queue<TreeNode*> que;   // 存放一层的数据
    int depth = 0;          // 记录深度
public:
    int minDepth(TreeNode* root) {
        return BFS(root);
    }
    // BFS
    int BFS(TreeNode* root) {
        if (root == nullptr) return 0;
        // 先放入一个元素
        que.push(root);
        depth++;
        // 开始一层层遍历
        while (!que.empty()) {
            int size = que.size();
            // 一个个遍历, 并把下一层加入
            for (int i = 0; i < size; ++i) {
                TreeNode* cur = que.front(); que.pop();
                // 判断是否为叶子节点
                if (cur->left == nullptr && cur->right == nullptr) {
                    return depth;
                }
                // 把子节点加入
                if (cur->left != nullptr) que.push(cur->left);
                if (cur->right != nullptr) que.push(cur->right);
            }
            depth++;
        }
        return depth;
    }
};

🥂 752. 打开转盘锁 [字符串数组] [最小距离] (BFS)

cpp 复制代码
class Solution {
private:
    queue<string> que;              // 存放一行的数据
    int step = 0;                   // 需要的步数
    unordered_set<string> uset;     // 记录死亡密码
    unordered_set<string> visited;  // 防止走回头路
public:
    int openLock(vector<string>& deadends, string target) {
        for (auto& dead : deadends) {
            uset.insert(dead);
        }
        return BFS(deadends, target);
    }
    // BFS
    int BFS(vector<string>& deadends, string target) {
        // 先放进入一个
        que.push("0000");
        visited.insert("0000");
        // 开始一层层遍历
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                string cur = que.front(); que.pop();
                // 判断是否到死亡节点
                if (uset.count(cur)) continue;
                // 如果到达终点
                if (cur == target) return step;
                // 将相邻节点加入
                for (int j = 0; j < 4; ++j) {
                    string up = cur, down = cur;
                    up[j] = up[j] == '9' ? '0' : up[j] + 1;
                    down[j] = down[j] == '0' ? '9' : down[j] - 1;
                    if (!visited.count(up)) {
                        que.push(up);
                        visited.insert(up);
                    }
                    if (!visited.count(down)) {
                        que.push(down);
                        visited.insert(down);
                    }
                }
            }
            step++;
        }
        // 这里就是找不到了
        return -1;
    }
};

🍻 层序遍历

🥂 102. 二叉树的层序遍历 [二叉树] [遍历] (BFS)

cpp 复制代码
class Solution {
private:
    queue<TreeNode*> que;           // BFS 队列
    vector<vector<int>> res;        // 最终结果
    vector<int> layer;              // 每一层
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (root == nullptr) return res;
        // 先放头节点
        que.push(root);
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                // 取出节点, 放入下一层节点
                TreeNode* cur = que.front(); que.pop();
                layer.push_back(cur->val);
                if (cur->left != nullptr) que.push(cur->left);
                if (cur->right != nullptr) que.push(cur->right);
            }
            res.push_back(layer);
            // 清空上一层节点
            layer.clear();
        }
        return res;
    }
};
相关推荐
云卓SKYDROID4 分钟前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香28 分钟前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童32 分钟前
双指针算法习题解答
算法
想要打 Acm 的小周同学呀41 分钟前
LRU缓存算法
java·算法·缓存
劲夫学编程2 小时前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪2 小时前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_4 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师6 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉6 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer6 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法