Notas de cepillado de Leetcode (C++) - árbol binario

Notas de cepillado de Leetcode (C++) - árbol binario

Ordene las ideas en el proceso de repasar las preguntas, resúmalas y compártalas aquí.
dirección de github: https://github.com/lvjian0706/Leetcode-solutions
El proyecto de github se creó recientemente, y el código y las ideas se cargarán uno tras otro. El código está basado en C++ y python. Al mismo tiempo, el algoritmo de clasificación básico también se clasificará y cargará.

102. Recorrido de orden de nivel del árbol binario

Dado un árbol binario, devuelva los valores de nodo obtenidos al recorrerlo en orden. (es decir, capa por capa, visite todos los nodos de izquierda a derecha).

Ejemplo:
Árbol binario: [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
devuelve su resultado de recorrido de nivel:
[
[3],
[9,20],
[15,7]
]

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    层序遍历:宽度优先搜索(bfs)
    1. 创建队列存放二叉树的节点以及节点对应的level,其中使用pair来存放二叉树的节点以及节点对应的level;
    2. 如果树为空,返回空ans数组;
    3. 首先将<root, 0>进栈,并且定义idx为当前level;
    4. 循环遍历队头中的元素:
    4.1 使用pnode存储队头元素,保存队头元素的值以及level,并将队头元素出栈;
    4.2 判断队头元素的level与idx是否一致,一致说明队头元素与之前的元素属于相同的level,直接push进subAns;否则说明队头元素与之前的元素属于不同的level,更新idx,先将subAnspush进ans中,再清空subAns,并将队头元素的值push进去;
    4.3 判断是否还有左右孩子,有的话将左右孩子和对应的level(nowIdx+1)存入队列;
    5. 将最后一组subAns的值push进ans中,返回ans;
    */
    vector<vector<int>> levelOrder(TreeNode* root) {
    
    
        queue<pair<TreeNode*, int>> qnode;
        vector<vector<int>> ans;
        if(!root) return ans;
        vector<int> subAns;
        qnode.push(make_pair(root, 0));
        int idx = 0;
        while(!qnode.empty()){
    
    
            pair<TreeNode*, int> pnode = qnode.front();
            qnode.pop();
            TreeNode* node = pnode.first;
            int nowIdx = pnode.second;
            if(nowIdx != idx){
    
    
                ans.push_back(subAns);
                subAns.clear();
                idx = nowIdx;
            }
            subAns.push_back(node->val);
            if(node->left) qnode.push(make_pair(node->left, nowIdx+1));
            if(node->right) qnode.push(make_pair(node->right, nowIdx+1));
        }
        ans.push_back(subAns);
        return ans;
    }
};

103. Nivel de zigzag transversal del árbol binario

Dado un árbol binario, devuelva un recorrido de nivel en zigzag de sus valores de nodo. (Es decir, primero recorra de izquierda a derecha, luego de derecha a izquierda, y así sucesivamente, alternando entre capas).

Por ejemplo:
dado un árbol binario [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
devuelve un recorrido de jerarquía en zigzag de la siguiente manera:
[
[3],
[20,9],
[ 15,7 ]
]

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    层序遍历:宽度优先搜索(bfs)
    1. 创建队列存放二叉树的节点以及节点对应的level,其中使用pair来存放二叉树的节点以及节点对应的level;
    2. 如果树为空,返回空ans数组;
    3. 首先将<root, 0>进栈,并且定义idx为当前level;
    4. 定义flag变量用于判断当前行是从左往右还是从右往左进行遍历;
    5. 循环遍历队头中的元素:
    5.1 使用pnode存储队头元素,保存队头元素的值以及level,并将队头元素出栈;
    5.2 判断队头元素的level与idx是否一致,一致说明队头元素与之前的元素属于相同的level,通过flag的状态判断是将当前元素push到数组末尾还是insert到数组头部;
    5.3. 否则说明队头元素与之前的元素属于不同的level,更新idx,先将subAns插入ans的第一个位置,再清空subAns,并通过flag的状态判断是将当前元素push到数组末尾还是insert到数组头部;;
    5.4 判断是否还有左右孩子,有的话将左右孩子和对应的level(nowIdx+1)存入队列;
    6. 将最后一组subAns的值插入ans的第一个位置,返回ans;
    */
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    
    
        vector<vector<int>> ans;
        if(!root) return ans;
        vector<int> subAns;
        queue<pair<TreeNode*, int>> nodeQ;
        nodeQ.push(make_pair(root, 0));
        int idx = 0;
        bool flag = true;
        while(!nodeQ.empty()){
    
    
            TreeNode* node = nodeQ.front().first;
            int nowIdx = nodeQ.front().second;
            nodeQ.pop();
            if(nowIdx!=idx){
    
    
                ans.push_back(subAns);
                subAns.clear();
                flag = !flag;
                idx = nowIdx;
            }
            if(flag) subAns.push_back(node->val);
            else subAns.insert(subAns.begin(), node->val);
            if(node->left) nodeQ.push(make_pair(node->left, nowIdx+1));
            if(node->right) nodeQ.push(make_pair(node->right, nowIdx+1));
        }
        ans.push_back(subAns);
        return ans;
    }
};

104. Profundidad máxima del árbol binario

Dado un árbol binario, encuentre su profundidad máxima.

La profundidad de un árbol binario es el número de nodos en el camino más largo desde el nodo raíz hasta el nodo hoja más alejado.

Explicación: un nodo hoja hace referencia a un nodo sin nodos secundarios.

Ejemplo :
dado un árbol binario [3,9,20,null,null,15,7],
3/9 20/15 7 devuelve su profundidad máxima de 3
.



/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    深度优先搜索:
    1. 传入参数:当前节点以及上一层节点的深度;
    2. 如果当前节点为空,返回上一层节点的深度;
    3. 否则,采用分治思想,递归计算左子树的深度和右子树的深度,返回深度最大值;
    */
    int dfs(TreeNode* root, int depth){
    
    
        if(!root) return depth;
        int leftDepth = dfs(root->left, depth+1);
        int rightDepth = dfs(root->right, depth+1);
        return max(leftDepth, rightDepth);
    }

    /*
    树的遍历:求树的最长路径的深度,可以使用深度优先搜索(dfs)
    */
    int maxDepth(TreeNode* root) {
    
    
        int ans = dfs(root, 0);
        return ans;
    }
};

107. Recorrido de nivel de árbol binario II

Dado un árbol binario, devuelva un recorrido de nivel ascendente de sus valores de nodo. (Es decir, atravesar de izquierda a derecha capa por capa desde la capa donde se encuentra el nodo hoja hasta la capa donde se encuentra el nodo raíz)

Por ejemplo:
dado un árbol binario [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
devuelve su recorrido de nivel ascendente como:
[
[15,7],
[9,20 ] ,
[3]
]

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    层序遍历:宽度优先搜索(bfs)
    1. 创建队列存放二叉树的节点以及节点对应的level,其中使用pair来存放二叉树的节点以及节点对应的level;
    2. 如果树为空,返回空ans数组;
    3. 首先将<root, 0>进栈,并且定义idx为当前level;
    4. 循环遍历队头中的元素:
    4.1 使用pnode存储队头元素,保存队头元素的值以及level,并将队头元素出栈;
    4.2 判断队头元素的level与idx是否一致,一致说明队头元素与之前的元素属于相同的level,直接push进subAns;否则说明队头元素与之前的元素属于不同的level,更新idx,先将subAns插入ans的第一个位置,再清空subAns,并将队头元素的值push进去;
    4.3 判断是否还有左右孩子,有的话将左右孩子和对应的level(nowIdx+1)存入队列;
    5. 将最后一组subAns的值插入ans的第一个位置,返回ans;
    */
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
    
    
        vector<vector<int>> ans;
        if(!root) return ans;
        vector<int> subAns;
        queue<pair<TreeNode*, int>> nodeQ;
        nodeQ.push(make_pair(root, 0));
        int idx = 0;
        while(!nodeQ.empty()){
    
    
            TreeNode* node = nodeQ.front().first;
            int nowIdx = nodeQ.front().second;
            nodeQ.pop();
            if(nowIdx!=idx){
    
    
                ans.insert(ans.begin(), subAns);
                subAns.clear();
                idx = nowIdx;
            }
            subAns.push_back(node->val);
            if(node->left) nodeQ.push(make_pair(node->left, nowIdx+1));
            if(node->right) nodeQ.push(make_pair(node->right, nowIdx+1));
        }
        ans.insert(ans.begin(), subAns);
        return ans;
    }
};

110. Árbol binario equilibrado

Dado un árbol binario, determine si es un árbol binario de altura equilibrada.

En esta pregunta, un árbol binario equilibrado en altura se define como:

El valor absoluto de la diferencia de altura entre los subárboles izquierdo y derecho de cada nodo en un árbol binario no excede de 1.

Ejemplo 1:
dado un árbol binario [3,9,20,null,null,15,7]
3
/
9 20
/
15 7
devuelve verdadero.
Ejemplo 2:
dado un árbol binario [1,2,2,3,3,null,null,4,4]
1
/
2 2
/
3 3
/
4 4
devuelve falso.

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    计算二叉树的深度:
    1. 如果不存在该节点,返回0;
    2. 计算左子树深度和右子树深度;
    3. 该树的深度为左子树深度和右子树深度的最大值加1(1代表根节点深度);
    */
    int height(TreeNode* root){
    
    
        if(!root) return 0;
        int left = height(root->left);
        int right = height(root->right);
        return max(left, right)+1;
    }

    /*
    判断二叉树是否平衡:考虑到需要判断二叉树中每个节点并计算深度,可以使用深度优先搜索(dfs)
    1. 如果不存在节点,返回true;
    2. 判断左子树和右子树是否是平衡二叉树;
    3. 计算左子树深度和右子树深度;
    4. 当左子树和右子树都是平衡二叉树,且左子树深度和右子树深度差的绝对值不超过1时,返回true,否则,返回false;
    */
    bool isBalanced(TreeNode* root) {
    
    
        if(!root) return true;
        bool leftBanlanced = isBalanced(root->left);
        bool rightBanlanced = isBalanced(root->right);
        int lheight = height(root->left);
        int rheight = height(root->right);
        if(leftBanlanced && rightBanlanced && lheight <= rheight+1 && rheight <= lheight+1){
    
    
            return true;
        }
        else return false;
    }
};

124. Suma máxima de ruta en árbol binario

Dado un árbol binario no vacío, devuelve su suma de ruta máxima.

En esta pregunta, un camino se define como una secuencia que comienza en cualquier nodo del árbol y llega a cualquier nodo. La ruta contiene al menos un nodo y no pasa necesariamente por el nodo raíz.

Ejemplo 1:
Entrada: [1,2,3]
1/2 3 Salida: 6 Ejemplo 2: Entrada : [-10,9,20,null,null,15,7
] -10/9 20/15 7 Salida : 42









/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    计算每个节点的贡献值,同时使用全局变量maxSum记录遍历到当前节点时的最大路径和:
    1. 当该节点为空时,贡献值为0;
    2. 计算该节点左子树和右子树的贡献值,其中,需要保证贡献值大于等于0(贡献值为负数时,不将该子树的路径和加入到最终的结果中,因此,相当于加0);
    3. 计算该节点的最大路径和,更新maxSum;
    4. 返回该节点的贡献值(该节点的值加max(左子树的最大路径和,右子树的最大路径和));
    */
    int nodeGain(TreeNode* root, int &maxSum){
    
    
        if(!root) return 0;
        int leftSum = max(nodeGain(root->left, maxSum), 0);
        int rightSum = max(nodeGain(root->right, maxSum), 0);
        int nowSum = root->val + leftSum + rightSum;
        maxSum = max(maxSum, nowSum);
        return root->val + max(leftSum, rightSum);
    }
    /*
    最大路径和:需要进行深度遍历,使用深度优先搜索(dfs)
    1. 定义maxSum变量实时保存每个节点的最大路径和;
    2. 计算每个节点的贡献值,同时使用全局变量maxSum记录遍历到当前节点时的最大路径和:
    3. 返回maxSum;
    */
    int maxPathSum(TreeNode* root) {
    
    
        int maxSum = INT_MIN;
        int rootPathSum = nodeGain(root, maxSum);
        return maxSum;
    }
};

236. Ancestro común más cercano del árbol binario

Dado un árbol binario, encuentre el ancestro común más cercano de dos nodos especificados en el árbol.

La definición del ancestro común más cercano en la Enciclopedia de Baidu es: "Para dos nodos p y q de un árbol con raíz T, el ancestro común más cercano se expresa como un nodo x, lo que satisface que x es el ancestro de p y q y la profundidad de x es lo más grande posible (un nodo también puede ser su propio ancestro)."

Ejemplo 1:
Entrada: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Salida: 3
Explicación: El nodo 5 más cercano y el nodo 1 El ancestro común es el nodo 3.
Ejemplo 2:
Entrada: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Salida: 5
Explicación: El nodo 5 y el nodo 4 más cercanos El ancestro común es el nodo 5. Porque, por definición, el nodo ancestro común más cercano puede ser el propio nodo.

Explicación:
Los valores de todos los nodos son únicos.
p y q son nodos diferentes y ambos existen en el árbol binario dado.

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    最近公共祖先:可以用深度优先遍历(dfs)
    注意:p、q 为不同节点且均存在于给定的二叉树中;
    1. 如果节点为空,直接返回NULL;
    2. 当遍历到p或q时,直接返回该节点;(找到了其中一个节点)
    3. 递归遍历,如果左子树中遍历到了某一个节点,返回该节点;右子树同理;
    4. 当左子树和右子树都存在某个节点时,返回根节点root;(找到了最近公共节点)
    5. 当只有左子树存在节点时,返回左子树的节点;(有可能只找到了一个节点,也有可能两个节点都在左子树);右子树同理;
    6. 否则,不存在两个节点,返回null;
    由于是自底向上,而且一定会存在p和q节点,因此在递归过程中最近公共节点会覆盖子节点
    */
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if(!root) return NULL;
        if(root->val==p->val || root->val==q->val) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if(left!=NULL && right!=NULL) return root;
        else if(left!=NULL) return left;
        else if(right!=NULL) return right;
        else return NULL;
    }
};


/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    
    
public:
    /*
    递归遍历节点,判断该节点是否是p或q的祖先,同时更新ans:
    1. 如果root不存在,返回false;
    2. 判断左孩子是否为p和q的公共节点以及右孩子是否为p和q的公共节点;
    3. 如果左右孩子同时为p和q的公共节点,或者root是q或者p中的一个且左右孩子中有一个为p和q的公共节点,则说明root为p和q的最近公共节点;
    4. 如果root是q或者p中的一个或者左右孩子中有一个为p和q的公共节点,则说明该节点是p或q的祖先,返回true;
    由于是自底向上判断,且一定存在p和q两个节点,因此找到的一定是最近公共节点;
    */
    bool isAncestor(TreeNode* root, TreeNode* p, TreeNode* q, TreeNode* &ans){
    
    
        if(!root) return false;
        bool isleft = isAncestor(root->left, p, q, ans);
        bool isright = isAncestor(root->right, p, q, ans);
        if((isleft && isright) || ((root->val==q->val || root->val==p->val) && (isleft || isright))){
    
    
            ans = root;
        }
        return isleft || isright || (root->val==q->val || root->val==p->val);
    }

    /*
    最近公共祖先:可以使用深度遍历的方法,使用深度优先搜索(dfs)
    1. 定义变量ans存放最近公共节点
    2. 定义函数isAncestor递归遍历节点,判断该节点是否是p或q的祖先,同时更新ans
    */
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        TreeNode* ans;
        bool isroot = isAncestor(root, p, q, ans);
        return ans;
    }
};

Supongo que te gusta

Origin blog.csdn.net/weixin_43273742/article/details/107733439
Recomendado
Clasificación