深搜(DFS)和广搜(BFS):初识问题状态

搜索的核心概念

这是思维逻辑中的一棵树
在这里插入图片描述
什么是深搜和广搜?
对于问题求解树的不同的遍历方式

什么是搜索剪枝和优化?
排除某些问题的求解树中的子树的遍历过程

设计搜索算法的核心关键点是什么?
设计问题求解树中的状态

广度遍历适合最优化问题

经典面试题 - 深搜广搜系列题目

993. 二叉树的堂兄弟节点

使用深搜

class Solution {
public:
    int dfs(TreeNode *root, int x, TreeNode *&father){
        if(root == nullptr) return -1;
        if(root->val == x) return 0;
        father = root;
        int l;
        l = dfs(root->left, x, father);
        if(l != -1) return l + 1;
        father = root;
        l = dfs(root->right, x, father);
        if(l != -1) return l + 1;
        return -1;
    }
    bool isCousins(TreeNode* root, int x, int y) {
        int d1, d2;
        TreeNode *father_x = nullptr, *father_y = nullptr;
        d1 = dfs(root, x, father_x);
        d2 = dfs(root, y, father_y);
        return d1 == d2 && father_x != father_y;
    }
};

使用广搜

class Solution {
public:
    struct Data{
        Data(TreeNode *node = nullptr, TreeNode *father = nullptr, int deepth = 0)
        :node(node), father(father), deepth(deepth) {}
        TreeNode *node, *father;
        int deepth;
    };
    bool isCousins(TreeNode* root, int x, int y) {
        int d1, d2;
        TreeNode *father_x = nullptr, *father_y = nullptr;
        queue<Data> q;
        q.push(Data(root, 0));
        while(!q.empty()){
            Data cur = q.front();
            if(cur.node->val == x) d1 = cur.deepth, father_x = cur.father;
            if(cur.node->val == y) d2 = cur.deepth, father_y = cur.father;
            if(cur.node->left) {
                q.push(Data(cur.node->left, cur.node, cur.deepth + 1));
            }
            if(cur.node->right) {
                q.push(Data(cur.node->right, cur.node, cur.deepth + 1));
            }
            q.pop();
        }
        return d1 == d2 && father_x != father_y;
    }
};

542. 01 矩阵

class Solution {
public:
    struct Data {
        Data(int i = 0, int j = 0, int k = 0)
        : i(i), j(j), k(k) {}
        int i, j, k;
    };
    void init_queue(
        queue<Data> &q, vector<vector<int>> &vis,
        int n, int m,
        vector<vector<int>> &mat
    ){
        for(int i = 0; i < n; i++){
            vis.push_back(vector<int>());
            for(int j = 0; j < m; j++){
                vis[i].push_back(-1);
            }
        }
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(mat[i][j]) continue;
                vis[i][j] = 0;
                q.push(Data(i, j, 0));
            }
        }
        return;
    }
    int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int n = mat.size(), m = mat[0].size();
        queue<Data> q;
        vector<vector<int>> vis;
        init_queue(q, vis, n, m, mat);
        while(!q.empty()){
            Data cur = q.front();
            for(int k = 0; k < 4; k++){
                int x = cur.i + dir[k][0];
                int y = cur.j + dir[k][1];
                if(x < 0 || x >= n) continue;
                if(y < 0 || y >= m) continue;
                if(vis[x][y] != -1) continue;
                vis[x][y] = cur.k + 1;
                q.push(Data(x, y, cur.k + 1));
            }
            q.pop();
        }
        return vis;
    };
};

1091. 二进制矩阵中的最短路径

  • continue的状态是用来排除非法状态的
class Solution {
public:
    struct Data {
        Data(int i = 0, int j = 0, int l = 0)
        : i(i), j(j), l(l) {}
        int i, j, l;
    };
    int dir[8][2] = { 
        0, 1, 1, 0, 0, -1, -1, 0,
        1, -1, -1, 1, 1, 1, -1, -1
    };
    int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
        int n = grid.size();
        vector<vector<int>> vis;
        for(int i = 0; i < n; i++){
            vis.push_back(vector<int>(n));
        }
        queue<Data> q;
        if(grid[0][0]) return -1;
        vis[0][0] = 1;
        q.push(Data(0, 0, 1));
        while(!q.empty()){
            Data cur = q.front();
            if(cur.i == n - 1 && cur.j == n -1) return cur.l;
            for(int k = 0; k < 8; k++){
                int x = cur.i + dir[k][0];
                int y = cur.j + dir[k][1];
                if(x < 0 || x >= n) continue;
                if(y < 0 || y >= n) continue;
                if(grid[x][y]) continue;
                if(vis[x][y]) continue;
                vis[x][y] = 1;
                q.push(Data(x, y, cur.l + 1));
            }
            q.pop();
        }
        return -1;
    }
};

752. 打开转盘锁

class Solution {
public:
    struct Data{
        Data(string s = "", int l = 0)
        : s(s), l(l){}
        string s;
        int l;
    };
    string getS(string &s, int i, int k){
        string ret = s;
        switch(k) {
            case 0: ret[i] += 1; break;
            case 1: ret[i] -= 1; break; 
        }
        if(ret[i] < '0') ret[i] = '9';
        if(ret[i] > '9') ret[i] = '0';
        return ret;
    }
    int openLock(vector<string>& deadends, string target) {
        queue<Data> q;
        unordered_set<string> h;
        for(auto x: deadends) h.insert(x);
        if(h.find("0000") != h.end()) return -1;
        h.insert("0000");
        q.push(Data("0000", 0));
        while(!q.empty()){
            Data cur = q.front();
            if(cur.s == target) return cur.l;
            for(int i = 0; i < 4; i++){
                for(int k = 0; k < 2; k++){
                    string t = getS(cur.s, i, k);
                    if(h.find(t) != h.end()) continue;
                    h.insert(t);
                    q.push(Data(t, cur.l + 1));
                }
            }
            q.pop();
        }
        return -1;
    }
};

130. 被围绕的区域

class Solution {
public:
    int n, m;
    int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
    void dfs(int i, int j, vector<vector<char>> &board){
        board[i][j] = 'o';
        for(int k = 0; k < 4; k++){
            int x = i + dir[k][0];
            int y = j + dir[k][1];
            if(x < 0 || x >= n) continue;
            if(y < 0 || y >= m) continue;
            if(board[x][y] != 'O') continue;
            dfs(x, y, board);
        }
        return ;
    };
    void solve(vector<vector<char>>& board) {
        n = board.size(), m = board[0].size();
        for(int i = 0; i < n; i++){
            if(board[i][0] == 'O') dfs(i ,0, board);
            if(board[i][m - 1] == 'O') dfs(i, m - 1, board);
        }
        for(int j = 0; j < m; j++){
            if(board[0][j] == 'O') dfs(0, j, board);
            if(board[n - 1][j] == 'O') dfs(n - 1, j, board);
        }
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(board[i][j] == 'O') board[i][j] = 'X';
                else if(board[i][j] == 'o') board[i][j] = 'O';
            }
        }
        return;
    }
};

494. 目标和

class Solution {
public:
    int dfs(int i, int target, vector<int> &nums){
        if(i == nums.size()){
            return target == 0;
        }
        int ans = 0;
        ans += dfs(i + 1, target - nums[i], nums); // +
        ans += dfs(i + 1, target + nums[i], nums); // -
        return ans;
    }
    int findTargetSumWays(vector<int>& nums, int target) {
        return dfs(0, target, nums);
    }
};

由于该程序效率太差,使用记忆化进行优化
数组和函数没有差别

class Solution {
public:
    typedef pair<int, int> PII;
    struct CMP {
        int operator()(const PII &a) const {
            return a.first ^ a.second;
        }
    };
    unordered_map<PII, int, CMP> h;
    int dfs(int i, int target, vector<int> &nums){
        if(i == nums.size()){
            return target == 0;
        }
        if(h.find(PII(i, target)) != h.end()){
            return h[PII(i, target)];
        }
        int ans = 0;
        ans += dfs(i + 1, target - nums[i], nums); // +
        ans += dfs(i + 1, target + nums[i], nums); // -
        h[PII(i, target)] = ans;
        return ans;
    }
    int findTargetSumWays(vector<int>& nums, int target) {
        h.clear();
        return dfs(0, target, nums);
    }
};

473. 火柴拼正方形

class Solution {
public:
    bool dfs(int ind, vector<int> &arr, vector<int> &ms){
        if(ind == -1) return true;
        for(int i = 0; i < 4; i++){
            if(arr[i] < ms[ind]) continue;
            if(arr[i] == ms[ind] || arr[i] >= ms[ind] + ms[0]){
                arr[i] -= ms[ind];
                if(dfs(ind - 1, arr, ms)) return true;
                arr[i] += ms[ind];
            }
        }
        return false;
    }
    bool makesquare(vector<int>& matchsticks) {
        sort(matchsticks.begin(), matchsticks.end());
        vector<int> arr(4);
        int sum = 0;
        for(auto x : matchsticks) sum += x;
        for(int i = 0; i < 4; i++) arr[i] = sum / 4;
        return dfs(matchsticks.size() - 1, arr, matchsticks);
    }
};

39. 组合总和

class Solution {
public:
    void dfs(int ind, int target, vector<int> &nums, vector<int> &buff, vector<vector<int>> &ret){
        if(target < 0) return;
        if(target == 0){
            ret.push_back(buff);
            return;
        }
        if(ind == nums.size()) return;
        dfs(ind + 1, target, nums, buff, ret);
        buff.push_back(nums[ind]);
        dfs(ind, target - nums[ind], nums, buff, ret);
        buff.pop_back();
        return;
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<int> buff;
        vector<vector<int>> ret;
        dfs(0, target, candidates, buff, ret);
        return ret;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值