昨天光写题忘写文章了,合并到今天一起写了///一共七个题///
【二叉搜索树中第k小元素】
给定一个二叉搜索树的根节点?root
?,和一个整数?k
?,请你设计一个算法查找其中第?k
?个最小元素(从 1 开始计数)。
思路:
搜索树!第一反应肯定是中序升序。方便起见我们先建立一个全局变量用来记录当前访问的节点是第几个,然后把中序遍历的板子糊上去就好啦。这题标mid我是不同意的,他真的不配。。。
class Solution {
public:
int cnt=0;
int kthSmallest(TreeNode* root, int k) {
stack<TreeNode*> stk;
while(root!=nullptr||!stk.empty()){
while(root!=nullptr){
stk.push(root);
root=root->left;
}
root =stk.top();
stk.pop();
if(++cnt==k)break;
root=root->right;
}
return root->val;
}
};
【二叉树右视图】
给定一个二叉树的?根节点?root
,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
思路:
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> ans;
queue<TreeNode*> q;
if (root)
q.push(root);
while (!q.empty()) {
int cnt = q.size();
TreeNode* cur = nullptr;
while (cnt) {
cur = q.front();
q.pop();
if (cur->left)
q.push(cur->left);
if (cur->right)
q.push(cur->right);
if (cnt-- == 1)
ans.push_back(cur->val);
}
}
return ans;
}
};
【二叉树展开为链表】
给你二叉树的根结点?root
?,请你将它展开为一个单链表:
TreeNode
?,其中?right
?子指针指向链表中下一个结点,而左子指针始终为?null
?。思路:
class Solution {
public:
void flatten(TreeNode* root) {
while(root){
if(root->left!=nullptr) {
TreeNode* R=root->left;
while(R->right) R=R->right;
R->right=root->right;
root->right=root->left;
root->left=nullptr;
}
root=root->right;
}
return;
}
};
class Solution {
public:
TreeNode* pre= nullptr;
void flatten(TreeNode* root) {
//先序遍历倒序:右左根
if(root==nullptr)return;
flatten(root->right);
flatten(root->left);
root->right=pre;
root->left=nullptr;
pre=root;
}
};
【从前序与中序遍历序列构造二叉树】
给定两个整数数组?preorder
?和?inorder
?,其中?preorder
?是二叉树的先序遍历,?inorder
?是同一棵树的中序遍历,请构造二叉树并返回其根节点。
思路:
这题虽然写了双解,但栈迭代那个我只能说我看懂了会写代码了...要我写题解思路实在是做不到,就写一下递归的思路算了qaq。
其实这个构造二叉树的过程用自然语言描述非常简单,我们最后做的不过是用代码翻译了这个过程:用前序找到当前的根节点,在中序找到根节点的位置,此时我们知道了左右子树各自的节点数量,which means我们知道了前序和中序序列中哪一段属于左子树,哪一段属于右子树,此时已经可以递归,算好参数传一下就搞定啦。(不过这个参数看起来真的蛮恶心的)
class Solution {
public:
TreeNode* helper(vector<int>& preorder, vector<int>& inorder, int l1,
int r1, int l2, int r2) {
//区间不合法退出递归
if (l1 > r1 || l2 > r2)
return nullptr;
//取先序首位
int curVal = preorder[l1];
//在中序找到
int i = l2;
for (; i <= r2; i++) {
if (inorder[i] == curVal)
break;
}
//构建根节点
TreeNode* root = new TreeNode(curVal);
//确定左子树节点数,更新左子树区间,递归构建
root->left = helper(preorder, inorder, l1 + 1, i + l1 - l2, l2, i - 1);
//右子树同理
root->right = helper(preorder, inorder, i + l1 - l2 + 1, r1, i + 1, r2);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int s1 = preorder.size();
int s2 = inorder.size();
return helper(preorder, inorder, 0, s1 - 1, 0, s2 - 1);
}
};
【路径总和】
给定一个二叉树的根节点?root
?,和一个整数?targetSum
?,求该二叉树里节点值之和等于?targetSum
?的?路径?的数目。
路径?不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
思路:
这题也写了双解,从两个解都获得了一点思路的突破,可开心了。
class Solution {
public:
int cal(TreeNode* root, long long target) {
if (root == nullptr)
return 0;
return cal(root->left,target-root->val)+cal(root->right,target-root->val)+(root->val==target);
}
int pathSum(TreeNode* root, long long targetSum) {
if (root == nullptr)
return 0;
int ans = 0;
ans += cal(root, targetSum);
ans += pathSum(root->left, targetSum);
ans += pathSum(root->right, targetSum);
return ans;
}
};
class Solution {
private:
unordered_map<long long, int> prefixMap;
long long target;
public:
int pathSum(TreeNode* root, long long targetSum) {
prefixMap.clear();
target = targetSum;
prefixMap[0] = 1;
return recur(root, 0);
}
private:
int recur(TreeNode* node, long long curSum) {
if (node == nullptr) {
return 0;
}
int res = 0;
curSum += node->val;
res += prefixMap[curSum - target];
prefixMap[curSum]++;
res += recur(node->left, curSum);
res += recur(node->right, curSum);
prefixMap[curSum]--;
return res;
}
};
【二叉树最近公共祖先】
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
思路:
嗯这题我自己先造了一个小屎山qaq,虽然很屎,但自己写并一次性AC的快乐还是让我决定给这坨答辩留下一点记录。
class Solution {
public:
int index = 0;
unordered_map<TreeNode*, int> idx;
void dfs(TreeNode* root) {
if (root == nullptr)
return;
dfs(root->left);
idx.emplace(root, index++);
dfs(root->right);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
//建立中序哈希表
dfs(root);
int RIndex = idx[root];
int PIndex = idx[p];
int QIndex = idx[q];
//当p和q还在当前节点的同一侧时,继续循环
while ((PIndex < RIndex && QIndex < RIndex) ||
(PIndex > RIndex && QIndex > RIndex)) {
if (PIndex < RIndex && QIndex < RIndex) {
root = root->left;
RIndex = idx[root];
}
if (PIndex > RIndex && QIndex > RIndex) {
root = root->right;
RIndex = idx[root];
}
}
return root;
}
};
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==nullptr)return nullptr;
if(root==p||root==q)return root;
TreeNode* left=lowestCommonAncestor(root->left,p,q);
TreeNode* right=lowestCommonAncestor(root->right,p,q);
if(left==nullptr&&right==nullptr)return nullptr;
if(left&&right)return root;
return left? left:right;
}
};
【二叉树最大路径和】
二叉树中的?路径?被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中?至多出现一次?。该路径?至少包含一个?节点,且不一定经过根节点。
路径和?是路径中各节点值的总和。
给你一个二叉树的根节点?root
?,返回其?最大路径和?。
思路:
又是一个拓宽思路而且可以复用的题。由于本题在每个节点得到的计算结果(可能会向左右两边延伸的最大路径和)和每个节点需要传给上层函数的结果(至多向一边延伸的最大路径和)是不一样的,苯人想破头了甚至开始试图传pair给上层...套了三层函数终于解决了以后,官解告诉我,你在每个节点把要算的给算了,用个全局变量记一下,然后只把需要传递的传上去不就好了吗?啊,可恶,这样真的显得我很傻逼。
class Solution {
public:
int maxInsideSum = INT_MIN;
int dfs(TreeNode* root) {
if (root == nullptr)
return 0;
int L = dfs(root->left);
int R = dfs(root->right);
int curSum = L + R + root->val;
maxInsideSum = max(curSum, maxInsideSum);
int temp = max(L, R) + root->val;
return temp > 0 ? temp : 0;
}
int maxPathSum(TreeNode* root) {
dfs(root);
return maxInsideSum;
}
};