算法 - 回溯 / DFS / BFS

news/2024/7/20 21:24:58 标签: 算法, 深度优先, 宽度优先

文章目录

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

🍺 回溯

🍻 子集

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

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. 子集Ⅱ [有重数组] [子集] (回溯)

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. 组合总和 [无重数组] [组合] (回溯)

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. 组合总和Ⅱ [有重数组] [组合] (回溯)

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. 组合 [无重数组] [组合] (回溯)

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个相等的子集 [有重数组] [组合] (回溯)

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. 括号生成 [字符串数组] [括号] (回溯)

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. 解数独 [矩阵] [数独] (回溯)

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. 全排列 [无重数组] [排列] (回溯)

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. 全排列Ⅱ [有重数组] [排列] (回溯)

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皇后 [矩阵] [排列] (回溯)

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皇后Ⅱ [矩阵] [排列] (回溯)

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)

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) (序列化)

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)

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)

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)

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)

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)

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)

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)

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;
    }
};

http://www.niftyadmin.cn/n/5329228.html

相关文章

Linux学习记录——사십이 高级IO(3)--- Poll型服务器

文章目录 1、认识poll接口2、实现3、特点 1、认识poll接口 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);// pollfd结构 struct pollfd {int fd; /* file descriptor */short events; /* requested events */short revents; /* returned…

QSettings功能介绍及应用

一.QSetting介绍 QSettings类提供了一种持久的、与平台无关的应用程序设置存储功能。 QSettings能读写配置文件&#xff0c;当配置文件不存在时&#xff0c;可生成配置文件。 二.基本用法 QSettings 提供了简单易用的 API&#xff0c;下面介绍一些常用的操作&#xff1a; 1…

Redis面试系列-03

1. 为什么 Redis 集群的最大槽数是 16384 个&#xff1f; 在redis节点发送心跳包时需要把所有的槽放到这个心跳包中&#xff0c;以便让节点知道当前集群信息&#xff0c;即1638416k&#xff0c;在发送心跳包时使用char进行bitmap压缩后是2k&#xff08;2*8 (8bit)*1024(1k)16K…

免费开源OCR 软件Umi-OCR

Umi-OCR 是一款免费、开源、可批量的离线 OCR 软件&#xff0c;基于 PaddleOCR&#xff0c;适用于 Windows10/11 平台 免费&#xff1a;本项目所有代码开源&#xff0c;完全免费。方便&#xff1a;解压即用&#xff0c;离线运行&#xff0c;无需网络。高效&#xff1a;自带高效…

[ceph] ceph之分布式存储

分布式存储的类型 ●块存储&#xff08;例如硬盘&#xff0c;一般是一个存储被一个服务器挂载使用&#xff0c;适用于容器或虚拟机存储卷分配、日志存储、文件存储&#xff09; 就是一个裸设备&#xff0c;用于提供没有被组织过的存储空间&#xff0c;底层以分块的方式来存储数…

C++98,C++11、C++14 和 C++17,C++20,我应该用哪个C++标准?

选择使用哪个C++标准取决于你的项目需求和所支持的编译器版本。 gcc编译器:使用命令行选项-std=c++version来指定所需的C++标准,例如-std=c++11、-std=c++14或-std=c++17。如果编译器不支持指定的标准,它会给出错误提示。 Microsoft Visual C++编译器,可以查看官方文档来…

中科院自动化所:基于关系图深度强化学习的机器人多目标包围问题新算法

摘要&#xff1a;中科院自动化所蒲志强教授团队&#xff0c;提出一种基于关系图的深度强化学习方法&#xff0c;应用于多目标避碰包围(MECA)问题&#xff0c;使用NOKOV度量动作捕捉系统获取多机器人位置信息&#xff0c;验证了方法的有效性和适应性。研究成果在2022年ICRA大会发…

低代码开发应用解锁旅游业的创新潜力

低代码开发平台的兴起为旅游业带来了许多机遇和挑战。本文将探讨旅游业如何利用低代码开发应用来创造更好的用户体验、提高效率以及应对竞争压力。 近年来&#xff0c;旅游业一直保持着快速增长的势头。随着全球旅游市场的扩大和游客的需求变得更加多样化&#xff0c;旅游企业面…