四十、LeetCode第四十题(230)
二叉搜索树中第k小的元素
给定一个二叉搜索树的根节点 root
,和一个整数 k
,请你设计一个算法查找其中第 k
个最小元素(从 1 开始计数)。
很简单,中序遍历,遍历到第k个元素就好了
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
stack<TreeNode*> stk;
while(root || !stk.empty()){
while(root){
stk.push(root);
root = root->left;
}
--k;
if (k == 0) {
break;
}
root = root->right;
}
return root->val;
}
};
四十一、LeetCode第四十一题(199)
二叉树的右视图
给定一个二叉树的 根节点 root
,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
这道题我脑袋短路了,一开始直接想的是遍历右子树就好了,右子树没有了再遍历左子树,结果发现左子树更深的话就漏掉了。看了提示才想起来层序遍历,也就是广度优先搜索,遍历每一层,取出来每一层的最后元素就好了,代码如下:就是在层序遍历的基础上把每一层的最后一个元素存下来,就得到结果了。队列的基础操作都用上了。(我觉得官方题解给复杂了)
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
if(!root) return res;
//层序遍历
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
int n = q.size();
res.push_back(q.back()->val);
for(int i = 1; i<=n; i++){
TreeNode* p = q.front();
q.pop();
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
}
}
return res;
}
};
注意一般开始都要判断以下root是否为空,不然总是报错:runtime error: member access within null pointer of type 'TreeNode' (solution.cpp)
四十二、LeetCode第四十二题(114)
二叉树展开为链表
给你二叉树的根结点 root
,请你将它展开为一个单链表:
- 展开后的单链表应该同样使用
TreeNode
,其中right
子指针指向链表中下一个结点,而左子指针始终为null
。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。
这道题首先分析肯定与前序遍历有关,常规思路是,前序遍历二叉树存下节点的值,再创建一个链表按顺序存进去,代码如下:
class Solution {
public:
void flatten(TreeNode* root) {
//TreeNode* head = root;
if(root == nullptr) return;
TreeNode* pre = root;
vector<int> s;
stack<TreeNode*> stk;
while(root || !stk.empty()){
while(root){
stk.push(root);
s.push_back(root->val);
root = root->left;
}
root = stk.top();
stk.pop();
root = root->right;
}
for(int i = 1; i<s.size(); i++){
TreeNode *p = new TreeNode(s[i]);
pre->right = p;
pre->left = nullptr;
pre = p;
}
}
};
或者是在前序遍历的过程中,边遍历边展开为链表,这个要修改前序遍历的方式,只能用栈的方法,不能递归。. - 力扣(LeetCode)
另外就是递归的方法:反前序遍历,即首先得到的是前序遍历的最后一个节点,存为pre,然后把倒数第二个节点的右子树存在pre,回溯的思想。
class Solution {
public:
TreeNode *pre;
void flatten(TreeNode* root) {
//递归
if(!root) return;
flatten(root->right);
flatten(root->left);
root->right = pre;
root->left = nullptr;
pre = root;
}
};
另外评论区有一个很棒的解法:直接把左子树的最右节点连接到根的右节点,再把根的右子树连接改成左子树,根移动到右节点,依次循环到null也就是右子树的底部
class Solution {
public void flatten(TreeNode root) {
while (root != null) {
TreeNode move = root.left;
while (move != null && move.right != null) {
move = move.right;
}
if (move != null) {
move.right = root.right;
root.right = root.left;
root.left = null;
}
root = root.right;
}
}
}
四十三、LeetCode第四十三题(105)
从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder
和 inorder
,其中 preorder
是二叉树的先序遍历, inorder
是同一棵树的中序遍历,请构造二叉树并返回其根节点。
这道题最容易想到的方式,就是递归吧,首先先序遍历的第一个节点一定是根节点,然后在中序遍历中找到根节点,左边就对应着左子树,右边就对应右子树,而先序遍历可以划分为根+左子树+右子树,这样划分数组,就可以对左右子树进行递归,代码如下:
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(!preorder.size()) return nullptr;
TreeNode *root = new TreeNode(preorder[0]);
int iter = 0;
for(int i = 0; i<inorder.size(); i++){
if(inorder[i] == preorder[0]){
iter = i;
break;
}
}
vector<int> in1;
for(int i = 0; i<iter; i++){
in1.push_back(inorder[i]);
}
vector<int> pre1;
for(int i = 1; i<=in1.size(); i++){
pre1.push_back(preorder[i]);
}
vector<int> in2;
for(int i = iter+1; i<inorder.size(); i++){
in2.push_back(inorder[i]);
}
vector<int> pre2;
for(int i = in1.size()+1; i<preorder.size(); i++){
pre2.push_back(preorder[i]);
}
root->left = buildTree(pre1, in1);
root->right = buildTree(pre2, in2);
return root;
}
};
有一说一这种递归真的超级慢,官方给出了用哈希表的方式辅助查找然后递归,另外还有非递归的方法 . - 力扣(LeetCode)
四十四、LeetCode第四十四题(236)
二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
题目真是做的怀疑人生。
看解答了
递归:首先判断根是否为空,p或q是否为根节点,任一成立都是直接返回root
然后递归。在左右子树里面找p,q,找到了就返回当前节点,没找到就返回root
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == nullptr || root == p || root == q) return root;
TreeNode *left = lowestCommonAncestor(root->left, p, q);
TreeNode *right = lowestCommonAncestor(root->right, p ,q);
if(left == nullptr) return right;
if(right == nullptr) return left;
return root;
}
};
这么简洁的代码,我怎么就想不出来啊
另一种方法:存储父节点,指路. - 力扣(LeetCode)
四十五、LeetCode第四十五题(124)
二叉树中的最大路径和
二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root
,返回其 最大路径和 。
没做出来看的题解
这个作者:Ikaruga 讲的很清晰
class Solution {
public:
int maxGain(TreeNode *root, int& maxNum){
if(root == nullptr) return 0;
int l = maxGain(root->left, maxNum);
int r = maxGain(root->right, maxNum);
int cur = root->val + max(0, l) + max(0, r);
int sec = root->val + max(0, max(l, r));
maxNum = max(maxNum, max(cur, sec));
return sec;
}
int maxPathSum(TreeNode* root) {
int maxNum = INT_MIN;
maxGain(root, maxNum);
return maxNum;
}
};
难度hard,等我进阶归来再二刷。