速通DFS

105. 从前序与中序遍历序列构造二叉树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    unordered_map<int,int> index;

public:
    TreeNode* mybuildTree(vector<int>& preorder, vector<int>& inorder,int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
        if (preorder_left>preorder_right){
            return NULL;
        }

        int preorder_root = preorder_left;
        int inorder_root = index[preorder[preorder_root]];

        TreeNode* root = new TreeNode(preorder[preorder_root]);
        int size_left_subtree= inorder_root-inorder_left;

        root->left = mybuildTree(preorder,inorder,preorder_left+1,preorder_left+size_left_subtree,inorder_left,inorder_root-1);

        root->right= mybuildTree(preorder,inorder,preorder_left+size_left_subtree+1,preorder_right,inorder_root+1,inorder_right);
        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        // 构造哈希映射,帮助我们在中序遍历种快速定位根节点
        for (int i = 0; i < n; ++i) {
            index[inorder[i]] = i;
        }
        return mybuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
    }


};

感觉问题还是在于递归中需要注意:每次递归传递的数值分为左子树和右子树的起点值与终点值,并在每次迭代的过程中找到其中的 种子节点。

其实前序序列就是一个不断通过第一个数来确定中间种子节点的数

随后通过哈希字典不断查找该种子在中序序列的值,从而确定迭代函数中的各自参数值。

为什么说是DFS,主要还是在于其不断递归是从最左的节点开始不断递归;
因为是根据前序遍历来确定种子节点,所以在具体过程中还是先确定种子节点然后不断向左的最深处探索

附上官方的DFS:

class Solution {
private:
    unordered_map<int, int> index;

public:
    TreeNode* myBuildTree(const vector<int>& preorder, const vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
        if (preorder_left > preorder_right) {
            return nullptr;
        }
        
        // 前序遍历中的第一个节点就是根节点
        int preorder_root = preorder_left;
        // 在中序遍历中定位根节点
        int inorder_root = index[preorder[preorder_root]];
        
        // 先把根节点建立出来
        TreeNode* root = new TreeNode(preorder[preorder_root]);
        // 得到左子树中的节点数目
        int size_left_subtree = inorder_root - inorder_left;
        // 递归地构造左子树,并连接到根节点
        // 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root->left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
        // 递归地构造右子树,并连接到根节点
        // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
        root->right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        // 构造哈希映射,帮助我们快速定位根节点
        for (int i = 0; i < n; ++i) {
            index[inorder[i]] = i;
        }
        return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solutions/255811/cong-qian-xu-yu-zhong-xu-bian-li-xu-lie-gou-zao-9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


112.路径之和

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool haxPathSum(TreeNode* root, int targetSum) {
        

        if (root->left==NULL && root->right == NULL && targetSum==0)
        return true;
        if (root->left==NULL && root->right==NULL && targetSum!=0)
        return false;

        if (root->left){
            targetSum=targetSum-root->left->val;
            if(haxPathSum(root->left,targetSum)) return true;
            targetSum=targetSum+root->left->val;
        }

        if (root->right){
            targetSum=targetSum-root->right->val;
            if(haxPathSum(root->right,targetSum)) return true;
            targetSum=targetSum+root->right->val;
        }
        return false;
    }
    bool hasPathSum(TreeNode* root, int targetSum){
        if(root==NULL) return false;

        
        return haxPathSum( root,  targetSum-root->val);
        
        //在开始回溯的时候,一定不要忘了把初始的值就先删了。
   }
};

98.验证搜索二叉树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    private :
    long long x= LONG_MIN; //这边还是设定了一个比Int型更小的Long放置在最左侧;这样可以给最左子树的节点进行狠狠比较!
public:
    bool isValidBST(TreeNode* root) {
        if(root==NULL) return true;
      bool Left=true;
      bool Right= true;
        if(root->left!=NULL){
           Left =   isValidBST(root->left); //向左深搜
        }


        if (root->val > x){
            x=root->val;
        }
        else return false; //中的时候进行一个狠狠处理;这边也复习了一下处理节点和遍历顺序之前的关系;
        //其实我在不断深搜节点的过程中,处理过程(或许是这道题的比较数值、或许是把这个数加入到某个数组之中),这件事情本身就是一个中节点

        if(root->right!=NULL){
           Right =   isValidBST(root->right);
        }  //向右深搜


        return Left && Right; //回归向左深搜和向右深搜的与值!

    }
};

494. 目标和

class Solution {
public:
    int count = 0;

    int findTargetSumWays(vector<int>& nums, int target) {
        backtrack(nums, target, 0, 0);
        return count;
    }

    void backtrack(vector<int>&nums, int target, int index,int sum){
        if(index==nums.size()){
            if(sum==target){count ++;}
            return;
        }

        backtrack(nums, target, index + 1, sum + nums[index]); //这种就是类似于二叉树,随后不断的向左深度搜索,随后再向右;狠狠学习了DFS!
        backtrack(nums, target, index + 1, sum - nums[index]);
    }
};

797. 所有可能的路径(DFS标准习题)

class Solution {

private:
    vector<vector<int>> result;
    vector<int> path;

    void dfs (vector<vector<int>>& graph ,int x){
        if (x == graph.size()-1){ //这边注意一定要减一,从而在具体书写的时候才能确定终点的位置,!!!千万注意返回节点所在的数值位置
            result.push_back(path);
            return;//在push_back一条结果后一定要及时的return!
        }

        for(int i=0;i<graph[x].size();i++){ //很妙的地方深搜就是深搜在于每次深搜传进去的数值对应其下面的该行每个值!,所以是x!
            path.push_back(graph[x][i]); //这边还是记得要pushback
            dfs(graph,graph[x][i]);
            path.pop_back(); //在深搜一步步回来的时候记得pop回来!
        }

    }


public:
    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
        path.push_back(0);
        dfs(graph,0);
        
        return result;
    }
};

547. 省份数量

class Solution {

private:
    void dfs(vector<vector<int>>& isConnected,int i,vector<bool>& visited){
        visited[i]=true;
        for(int j=0; j<isConnected.size();j++){
            if(isConnected[i][j]==1 && visited[j]==false){
                //visited[j]=true; //这边其实就是因为额外定义了一个全局变量visited,随后通过一次次读取该数组内逐个岛屿是否已读 作为循环的终止条件。
                dfs(isConnected,j,visited);
            }
        }
    }
    

public:
    int findCircleNum(vector<vector<int>>& isConnected) {

        int n= isConnected.size();
        
        vector<bool> visited(n,false);
        int provinces = 0;

        for (int i=0;i<n;i++){
            if(!visited[i]){
                dfs(isConnected,i,visited);
                provinces++;
            }

        }
        return provinces;
    }
};

200. 岛屿数量

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<bool>> visited = vector<vector<bool>>(n, vector<bool>(m, false)); 

        int result = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (!visited[i][j] && grid[i][j] == '1') {  
                    visited[i][j] = true;
                    result++; // 遇到没访问过的陆地,+1
                    dfs(grid, visited, i, j); // 将与其链接的陆地都标记上 true
                }
            }
        }
        return result;
    }


};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值