五月训练 Day18

0. Leetcode 2236. 判断根结点是否等于子结点之和

给你一个 二叉树 的根结点 root,该二叉树由恰好 3 个结点组成:根结点、左子结点和右子结点。
如果根结点值等于两个子结点值之和,返回 true ,否则返回 false 。

分析与解答

干就完事儿了

/**
 * 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 checkTree(TreeNode* root) {
        return root->val == (root->left->val + root->right->val);
    }
};

1. Leetcode 面试题 04.10. 检查子树

检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。
如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。
注意:此题相对书上原题略有改动。

分析与解答

解法 1:
首先想到的解法是遍历两个树后,通过寻找 T 1 T1 T1 中的子串 T 2 T2 T2,确定 T 2 T2 T2 是否为子树:

/**
 * 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:
	// 中序遍历树
    vector<int> searchTree(TreeNode* root) {
        vector<int> result;
        if (root->left == nullptr && root->right == nullptr) {
            result.push_back(root->val);
            return result;
        }
        
        if (root->left) {
            vector<int> left = searchTree(root->left);
            for (auto num: left) {
                result.push_back(num);
            }
        }
        result.push_back(root->val);
        if (root->right) {
            vector<int> right = searchTree(root->right);
            for (auto num: right) {
                result.push_back(num);
            }
        }
        
        return result;
    }

    bool checkSubTree(TreeNode* t1, TreeNode* t2) {
        if (t2 == nullptr) {
            return false;
        }
        vector<int> t1R = searchTree(t1);
        vector<int> t2R = searchTree(t2);
        if (t2R.size() > t1R.size()) {
            return false;
        }
        // 寻找子串
        for (int i = 0; i < t1R.size(); ++i) {
            if (t1R[i] == t2R[0]) {
                int sameNum(0);
                for (int j = 0; j < t2R.size(); ++j) {
                    if (t2R[j] != t1R[i + j]) {
                        break;
                    }
                    sameNum++;
                }
                if (sameNum == t2R.size()) {
                    return true;
                }
            }
        }
        
        return false;
    }
};

解法 2:哈希树
树也可以用哈希表示其唯一性。对每一个节点,计算以其为根节点的子树的哈希值,通过哈希值判断树 T 2 T2 T2 是否为树 T 1 T1 T1 的子树:

/**
 * 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:
    void calcHash(TreeNode* root) {
        if (root == nullptr) {
            return;
        }
        
        calcHash(root->left);
        calcHash(root->right);
        // 通过树节点值,计算相应的哈希值
        unsigned long long l = root->left? root->left->val: 1153470;
        unsigned long long r = root->right? root->right->val: 531287;
        root->val = (int) ((unsigned long long)root->val * 1196347 + l * 73451 + r);
    }
    
    bool find(TreeNode* t1, TreeNode* t2) {
        if (t1 == nullptr) {
            return false;
        }
        // 比较 哈希值 确定 t2 是否为 t1 的子树
        return t1->val == t2->val || find(t1->left, t2) || find(t1->right, t2);
    }

    bool checkSubTree(TreeNode* t1, TreeNode* t2) {
        calcHash(t1);
        calcHash(t2);
        
        if (t2 == nullptr) {
            return true;
        }
        
        return find(t1, t2);
    }
};

2. Leetcode 面试题 04.06. 后继者

设计一个算法,找出二叉搜索树中指定节点的“下一个”节点(也即中序后继)。
如果指定节点没有对应的“下一个”节点,则返回null。

分析与解答

解法 1:
首先想到的解法是遍历树后,在 vector 中寻找指定节点位置:

/**
 * 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 {
    vector<TreeNode*> nodeSet;
public:
    void searchTree(TreeNode* root, TreeNode* p) {
        if (root == nullptr) {
            return;
        }
        
        searchTree(root->left, p);
        nodeSet.push_back(root);
        searchTree(root->right, p);
    }

    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        searchTree(root, p);
        // 寻找指定节点位置
        for (int i = 0; i < nodeSet.size() - 1; ++i) {
            if (nodeSet[i]->val == p->val) {
                return nodeSet[i + 1];
            }
        }
        
        return nullptr;
    }
};

解法 2:标记查询
可以在搜索树时进行标记,若找到指定节点,则存储下一个要查找的节点,若无下一个节点,则返回空指针。

/**
 * 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 {
    bool findP; // 标记是否找到指定节点
    TreeNode* ret; // 后继节点存储位置
    
public:
    void searchTree(TreeNode* root, TreeNode* p) {
        if (root == nullptr) {
            return;
        }
        // 查找左子树
        searchTree(root->left, p);
        // 若找到指定节点且未填入后继节点,则当前根节点为指定节点的后继节点
        if (findP && ret == nullptr) {
            ret = root;
        }
        // 找到指定节点,将标记置为 true
        if (root->val == p->val) {
            findP = true;
        }
        // 查找右子树
        searchTree(root->right, p);
    }

    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        ret = nullptr;
        findP = false;
        searchTree(root, p);
        
        return ret;
    }
};

3. Leetcode 1110. 删点成林

给出二叉树的根节点 root,树上每个节点都有一个不同的值。
如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。
返回森林中的每棵树。你可以按任意顺序组织答案。

分析与解答

遍历树,若根节点在要删除的节点中,则将其子树加入结果向量;若左子树在要删除的节点中,则将根节点的左指针置为空;若右子树在要删除的节点中,则将根节点的右指针置为空:

/**
 * 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 {
    vector<TreeNode*> result;

public:
    void findTrees(TreeNode* root, vector<int>& to_delete) {
        if (root == nullptr) {
            return;
        }

        // 若根节点为要删除的节点,则将其左右子树放入 result 中
        auto it = find(to_delete.begin(), to_delete.end(), root->val);
        if (it != to_delete.end()) {
            if (root->left) {
                result.push_back(root->left);
            }

            if (root->right) {
                result.push_back(root->right);
            }
			// 根节点在结果集中,从结果集中删除
            auto ite = find(result.begin(), result.end(), root);
            if (ite != result.end()) {
                result.erase(ite);
            }
        }

        if (root->left) {
            findTrees(root->left, to_delete);
            // 若左子节点为要删除的节点,将根节点的左指针置为空
            auto it = find(to_delete.begin(), to_delete.end(), root->left->val);
            if (it != to_delete.end()) {
                root->left = nullptr;
            }
        }
        if (root->right) {
            findTrees(root->right, to_delete);
            // 若右子节点为要删除的节点,将根节点的右指针置为空
            auto it = find(to_delete.begin(), to_delete.end(), root->right->val);
            if (it != to_delete.end()) {
                root->right = nullptr;
            }
        }
    }

    vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
        auto it = find(to_delete.begin(), to_delete.end(), root->val);
        if (it == to_delete.end()) {
            result.push_back(root);
        }

        findTrees(root, to_delete);
        return result;
    }
};

总结

今日收获:哈希树与树的标记 😃

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值