1、LCR 047. 二叉树剪枝
题目信息:
- https://leetcode.cn/problems/pOCWxh/description/
给定一个二叉树 根节点 root ,树的每个节点的值要么是 0,要么是 1。请剪除该二叉树中所有节点的值为 0 的子树。
节点 node 的子树为 node 本身,以及所有 node 的后代。示例 1:
输入: [1,null,0,0,1]
输出: [1,null,0,null,1]
解释:
只有红色节点满足条件“所有不包含 1 的子树”。
右图为返回的答案。示例 2:
输入: [1,0,1,0,0,0,1]
输出: [1,null,1,null,1]
解释:示例 3:
输入: [1,1,0,1,1,0,1,0]
输出: [1,1,0,1,1,null,1]
解释:提示:
二叉树的节点个数的范围是 [1,200]
二叉树节点的值只会是 0 或 1
解题思路:
- 1、审题:输入一棵二叉树,二叉树中结点的值分别为0或1,要求将树中结点都为0的节点进行删除
- 2、解题:
- 将节点值为0的树删除,当叶子节点值为0时,该结点要删除
- 当一棵子树,根节点为0,且左右子节点也全是0的时候,这棵子树也需要删除
- 界面删除对于其父节点来说,就是将父节点的左右子节点的值设置为null
- 要删除左右子节点为0的树,使用后续遍历,先找到左右子节点,判断左右子树的节点值是否全是0,是0的话返回false,不全是0返回true
- 后续遍历的节点值,根据左右子树的返回值,判断其左右子节点是否需要删除
代码实现1:
bool pruneTreeTravel(TreeNode *node)
{if (node == nullptr){return false;}bool leftRes = pruneTreeTravel(node->left);bool rightRes = pruneTreeTravel(node->right);if (!leftRes){node->left = nullptr;}if (!rightRes){node->right = nullptr;}if (node->val == 0 && node->left == nullptr && node->right == nullptr){return false;}return true;
}TreeNode *pruneTree(TreeNode *root)
{bool res = pruneTreeTravel(root);if (!res){return nullptr;}return root;
}
代码实现2:
- 还是原来的思路,只不过返回值不再是bool值,而是直接返回左右子节点的值并且直接赋值,赋值后如果当前结点值也是0,说明这个节点也需要删除,直接返回null
TreeNode *pruneTree(TreeNode *root)
{if (root == nullptr){return nullptr;}root->left = pruneTree(root->left);root->right = pruneTree(root->right);if (root->val == 0 && root->left == nullptr && root->right == nullptr){return nullptr;}return root;
}
2、LCR 048. 二叉树的序列化与反序列化
题目信息:
- https://leetcode.cn/problems/h54YBf/description/
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。示例 1:
输入:root = [1,2,3,null,null,4,5]
输出:[1,2,3,null,null,4,5]示例 2:
输入:root = []
输出:[]示例 3:
输入:root = [1]
输出:[1]示例 4:
输入:root = [1,2]
输出:[1,2]提示:
输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,也可以采用其他的方法解决这个问题。
树中结点数在范围 [0, 104] 内
-1000 <= Node.val <= 1000
解题思路:
- 1、审题:对一个二叉树进行序列化与反序列化
- 2、解题:
- 二叉树的序列化操作,是输入一棵二叉树,处理后返回一串字符串,反序列化操作则是输入一串字符串,返回一棵二叉树
- 二叉树的序列化采用前序遍历二叉树的方式,当遇到空节点时,返回特殊字符#,非空节点则返回节点数值
- 反序列化则不断遍历字符串中的字符,使用一个int值标记当前遍历到的字符位置,通过不断获取字符串中的字符,来构造二叉树的结点,遇到字符为#,则说明需要构造空节点
代码实现:
class Codec
{
public:string serialize(TreeNode *root){if (root == nullptr){return "#";}std::string leftStr = serialize(root->left);std::string rightStr = serialize(root->right);return std::to_string(root->val) + "," + leftStr + "," + rightStr;}TreeNode *deserializeReal(const vector<string> &strs, int &i){string str = strs[i];i++;std::cout << "i=" << i << " ,str=" << str << std::endl;if (str == "#"){return nullptr;}TreeNode *node = new TreeNode(std::stoi(str));node->left = deserializeReal(strs, i);node->right = deserializeReal(strs, i);return node;}vector<string> splitString(const string &input){vector<string> result;size_t start = 0;size_t end = input.find(',');while (end != string::npos){result.push_back(input.substr(start, end - start));start = end + 1;end = input.find(',', start);}result.push_back(input.substr(start));return result;}TreeNode *deserialize(string data){int index = 0;vector<string> strs = splitString(data);return deserializeReal(strs, index);}
};
3、总结
- 二叉树剪枝,要求从叶子结点开始往上面根节点部分,判断是否存在全是为0的子树
- 这种情况适合使用后续遍历,先遍历左右子节点后遍历根节点,先判断左右子节点的值情况,再和根节点值进行判断处理。
- 二叉树的序列化,采用前序遍历,先遍历根节点再遍历左右子节点,获取到左右子树的序列化,最后和根节点一起序列化,遇到空节点返回#字符
- 反序列化对字符串进行分割,采用find方法进行截取保存到集合中,再遍历集合中的元素,同样按照前序遍历合成一棵二叉树。