DFS或BFS

DFS或BFS

  • 一、搜索二叉树
    • 1、hot100 - 98. 验证二叉搜索树(中序遍历)
    • 2、剑指 Offer 33. 二叉搜索树的后序遍历序列(递归分治)
    • 3、 剑指 Offer 36. 二叉搜索树与双向链表(中序遍历,新设pre、head节点)
  • 二、普通二叉树
    • 1、 hot100 - 102. 二叉树的层序遍历(BFS)
    • 2、hot100 - 114. 二叉树展开为链表(先序遍历:跟、左、右;辅助数组)
  • 三、二维数组
    • 1、hot100 - 200. 岛屿数量(DFS)

一、搜索二叉树

1、hot100 - 98. 验证二叉搜索树(中序遍历)

题目:https://leetcode-cn.com/problems/validate-binary-search-tree/

  • 中序遍历:左、根、右;对二叉搜索树来说,中序遍历的结果是升序的;
  • 检查当前节点的值是否大于前一个中序遍历得到的节点的值,若均大于说明这个序列是升序的。
  • 时间复杂度O(n)
    DFS方法:
/**
 * 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 flag = true;
    void dfs(TreeNode* root, stack<int> &st){
        if(root==nullptr) return ;
        dfs(root->left, st);
        if(!st.empty()){
            if(st.top() >= root->val){
                flag = false;
                return ;
            }
        }
        st.push(root->val);
        dfs(root->right, st);
    }
    bool isValidBST(TreeNode* root) {
        if(root==nullptr) return true;
        stack<int> st;
        dfs(root, st);
        return flag;
    }
};

官方代码(速度比递归快)

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        stack<TreeNode*> stack;
        long long inorder = (long long)INT_MIN - 1;//因为node的最小值为INT_MIN(-2^31)

        while (!stack.empty() || root != nullptr) {
        //类似dfs(root->left);
            while (root != nullptr) {
                stack.push(root);
                root = root -> left;
            }
            //当前根节点
            root = stack.top();
            stack.pop();
            // 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树
            if (root -> val <= inorder) {
                return false;
            }
            inorder = root -> val;
            //遍历当前根节点的右子树
            root = root -> right;
        }
        return true;
    }
};

2、剑指 Offer 33. 二叉搜索树的后序遍历序列(递归分治)

题目:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/
递归流程:

  • 终止条件:i>=j,说明此子树节点数量<=1,无需判别正确性,因此直接返回 true;
  • 递推工作
    1. 划分左右子树:遍历[i, j]区间元素,寻找第一个大于根节点的节点,索引记为m。此时可划分出左子树区间[i, m-1]、右子树区间[m, j-1]、根节点j;
    2. 判断是否为二叉搜索树
    - 左子树区间[i, m-1]内所有节点都应划分左右子树时已经证实左子树的正确性。
    - 右子树区间[m, j-1]内所有节点都应>postorder[j]。遍历右子树区间,当遇到<=postorder[j]的节点则跳出;通过判断跳出节点是否=j判断是否为二叉搜索树。
  • 时间复杂度O(n^2);最坏情况下,达到递归n遍,递归时间复杂度O(n),每次递归遍历时间复杂度O(n)。
class Solution {
public:
    bool dfs(int i, int j, const vector<int>& postorder){
        int m = i;
        if(i>=j) return true;
        //当前子树根节点为postorder[j](当前区间最后一个值),找到所有小于根节点的区间,该区间为当前根节点的左子树
        while(m<j){
            if(postorder[m]<postorder[j]) m++;
            else break;
        }
        // 判断右子树区间是否存在小于等于根节点的值,若存在该数组不是二叉搜索树的后续遍历结果
        int t = m+1;
        while(t<j){
            if(postorder[t]<=postorder[j]) return false;
            else t++;
        }
        return dfs(i, m-1, postorder) && dfs(m, j-1, postorder);
    }
    bool verifyPostorder(vector<int>& postorder) {
        return dfs(0, postorder.size()-1, postorder);
    }
};

3、 剑指 Offer 36. 二叉搜索树与双向链表(中序遍历,新设pre、head节点)

题目:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/
dfs(cur):递归法中序遍历:
中序遍历:

// 打印中序遍历
void dfs(Node* root) {
    if(root == nullptr) return;
    dfs(root->left); // 左
    cout << root->val << endl; // 根
    dfs(root->right); // 右
}
  1. 终止条件:当节点cur为空,代表越过叶节点,直接返回;
  2. 递归左子树
  3. 构建链表
    - 当pre为空时:代表正在访问链表头节点,记为head;
    - 当pre不为空时:修改双向节点引用,pre->right = cur , cur->left = pre;
    - 保存cur:更新pre=cur;
  4. 递归右子树
  • 时间复杂度:O(n)

  • 空间复杂度:O(n)

    • 最差情况下,即树退化为链表时,递归深度达到 N,系统使用 O(N) 栈空间。
/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;

    Node() {}

    Node(int _val) {
        val = _val;
        left = NULL;
        right = NULL;
    }

    Node(int _val, Node* _left, Node* _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
public:
    Node* pre, * head;
    void dfs(Node* cur){
        if(cur==NULL) return ;
        dfs(cur->left);
        if(pre==NULL) head = cur;
        else pre->right = cur;
        cur->left = pre;
        pre = cur;
        dfs(cur->right);
    }

    Node* treeToDoublyList(Node* root) {
        if(root==NULL) return NULL;
        dfs(root);
        head->left = pre;
        pre->right = head;
        return head;
    }
};

二、普通二叉树

1、 hot100 - 102. 二叉树的层序遍历(BFS)

题目:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/

  • 借助队列(queue)
  • 时间复杂度O(n)
  • 空间复杂度O(n)
/**
 * 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:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(root==nullptr) return {};
        queue<TreeNode*> qu;
        qu.push(root);
        while(!qu.empty()){
            int n = qu.size();
            vector<int> tmp;
            for(int i=0; i<n; i++){
                TreeNode* node = qu.front();
                tmp.push_back(node->val);
                if(node->left!=nullptr) qu.push(node->left);
                if(node->right!=nullptr) qu.push(node->right);
                qu.pop();
            }
            res.push_back(tmp);
        }
        return res;
    }
};

2、hot100 - 114. 二叉树展开为链表(先序遍历:跟、左、右;辅助数组)

题目:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
/**
 * 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:
    void dfs(TreeNode* root, vector<TreeNode* > &ve){
        if(root==nullptr) return ;
        ve.push_back(root);
        dfs(root->left, ve);
        dfs(root->right, ve);
    }
    void flatten(TreeNode* root) {
        if(root==nullptr) return ;
        vector<TreeNode* > ve;
        dfs(root, ve);
        int i;
        for(i=1; i<ve.size(); i++){
            ve[i-1]->left = nullptr;
            ve[i-1]->right = ve[i];
        }
        ve[i-1]->left = nullptr;
        ve[i-1]->right = nullptr;
    }
};

方法二:寻找前驱节点

  • 方法
    • 对于当前节点,如果其左子节点不为空,则在其左子树中找到最右边的节点将当前节点的右子节点赋给其左子节点的最右节点的右节点,当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设置为nullptr。
    • 对当前节点处理结束后,继续处理链表中的下一个节点,直到所有节点都处理结束。
  • 时间复杂度:O(n),在寻找前驱节点的过程中,每个节点最多被额外访问一次。
  • 空间复杂度:O(1)
class Solution {
public:
    void flatten(TreeNode* root) {
        TreeNode* cur = root;
        while(cur!=nullptr){
            if(cur->left!=nullptr){
                TreeNode* pre = cur->left;
                while(pre->right!=nullptr){
                    pre = pre->right;
                }
                pre->right = cur->right;
                cur->right = cur->left;
                cur->left = nullptr;
            }
            cur = cur->right;
        }
    }
};

三、二维数组

1、hot100 - 200. 岛屿数量(DFS)

题目:https://leetcode-cn.com/problems/number-of-islands/

  • 时间复杂度:O(MN)
  • 空间复杂度:O(MN)
class Solution {
public:
    int m, n;
    void dfs(int i, int j, vector<vector<char>>& grid){
        if(i<0 || i>=m || j<0 || j>=n) return ;
        if(grid[i][j]=='1'){
            grid[i][j] = '2';
            dfs(i-1, j, grid);
            dfs(i, j-1, grid);
            dfs(i+1, j, grid);
            dfs(i, j+1, grid);
        }        
    }
    int numIslands(vector<vector<char>>& grid) {
        m = grid.size();
        if(m == 0) return 0;
        n = grid[0].size();
        int res = 0;
        for(int i=0; i<m; i++){
            for(int j=0; j<n;j++){
                if(grid[i][j] == '1'){
                    dfs(i,j, grid);
                    res++;
                }
            }
        }
        return res;
    }
};

你可能感兴趣的:(leetcode,深度优先,宽度优先,算法)