预备知识:
二叉树 深度优先遍历
void dfs(TreeNode *root, vector<vector<int>>& result, int &path_sum, vector<int> &path, int sum){
if(!root){
return;
}
//此时访问,前序
dfs(root->left, result, path_sum, path, sum);
//此时访问,中序
dfs(root->right, result, path_sum, path, sum);
//此时访问,后序
}
1 路径之和 113
问题:返回所有路径之和==target的路径
思路:深度优先遍历,回溯思想,先在先序那里push每一个元素,判断和是否等于target,然后在后序(处理完左右节点后)把这个值去掉,
class Solution {
public:
vector<vector<int>> pathSum(TreeNode* root, int sum) {
vector<vector<int>> result;
vector<int> path;
int path_sum = 0;
dfs(root, result, path_sum, path, sum);
return result;
}
private:
void dfs(TreeNode *root, vector<vector<int>>& result, int &path_sum, vector<int> &path, int sum){
if(!root){
return;
}
path.push_back(root->val);
path_sum += root->val;
if(!root->left && !root->right && path_sum == sum){
result.push_back(path);
// return;
}
dfs(root->left, result, path_sum, path, sum);
dfs(root->right, result, path_sum, path, sum);
path.pop_back();
path_sum -= root->val;
}
};
2 最近的公共祖先 236
题目:找到两个节点最近的父节点
思路:和上题差不多,采用dfs搜索 搜索到这个节点就把这个路径保存下来,两个路径相比较。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
int finish = 0;
TreeNode *ret = 0;
vector<TreeNode *> path_p;
vector<TreeNode *> path_q;
vector<TreeNode*> temp;
int len=0;
dfs(root, p, finish, temp, path_p);
temp.clear();
finish = 0;
dfs(root, q, finish, temp, path_q);
if(path_p.size() < path_q.size()){
len = path_p.size();
}else{
len = path_q.size();
}
for(int i = 0; i< len; i++){
if(path_p[i]==path_q[i]){
ret = path_p[i];
}
}
return ret;
}
private:
void dfs(TreeNode *&root, TreeNode *&search, int &finish, vector<TreeNode *> &path, vector<TreeNode*>& result){
if(!root || finish){
return;
}
path.push_back(root);
if(search == root){
finish = 1;
result = path;
}
dfs(root->left, search, finish, path, result);
dfs(root->right, search, finish, path, result);
path.pop_back();
}
};
3 二叉树转链表 114
题目:给定一个二叉树,将它原地转为单链表,左置NULL,右边连起来
思路1:不满足原地,直接全部遍历一下,存到vector中,再连起来
class Solution {
public:
void flatten(TreeNode* root) {
vector<TreeNode*> ret;
dfs(root, ret);
ret.push_back(0);
for(int i =1;i<ret.size();i++){
ret[i-1]->left = NULL;
ret[i-1] -> right = ret[i];
}
}
private:
void dfs(TreeNode * &node, vector<TreeNode*> &ret){
if(!node){
return;
}
ret.push_back(node);
dfs(node->left, ret);
dfs(node->right, ret);
}
};
思路2:递归处理左子树和右子树,在中序处理,处理完左子树,处理根节点,根.left = , 根.right = 保存last用于连接右子树的开始
class Solution {
public:
void flatten(TreeNode *root) {
TreeNode *last = NULL;
preorder(root, last);
}
private:
void preorder(TreeNode *node, TreeNode *&last){
if (!node){
return;
}
if (!node->left && !node->right){
last = node;
return;
}
TreeNode *left = node->left;
TreeNode *right = node->right;
TreeNode *left_last = NULL;
TreeNode *right_last = NULL;
if (left){
preorder(left, left_last);
node->left = NULL;
node->right = left;
last = left_last;
}
if (right){
preorder(right, right_last);
if (left_last){
left_last->right = right;
}
last = right_last;
}
}
};
预备知识:
二叉树广度优先遍历
用一个队列存储节点,先进入队列的 优先遍历其左右孩子。
void BFS_print(TreeNode* root){
std::queue<TreeNode *> Q;
Q.push(root);
while(!Q.empty()){
TreeNode *node = Q.front();
Q.pop();
printf("[%d]\n", node->val);
if (node->left){
Q.push(node->left);
}
if (node->right){
Q.push(node->right);
}
}
}
4 侧面观察二叉树 199
输出 1,3,4,6
思路:
采用广度优先遍历(层次遍历),主要是建立层和节点的关系,把层和节点绑定到一起,建立view vector 每层都存一个值
如果view.size() 比深度小1的话就push进来,不是的话就改变这个值。
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
queue<pair<TreeNode *, int>> q;
if(root){
q.push(make_pair(root, 0));
}
vector<int> view;
int depth = 0;
while(!q.empty()){
TreeNode *temp = q.front().first;
depth = q.front().second;
q.pop();
if(view.size() == depth){
view.push_back(temp->val);
}else{
view[depth] = temp->val;
}
if(temp->left){
q.push(make_pair(temp->left, depth+1));
}
if(temp->right){
q.push(make_pair(temp->right, depth+1));
}
}
return view;
}
};
5 二叉树的层次遍历 102
题目: 每一层存到list中再存到最后结果中 , 返回list[ list, list, ...]
思路:按正常的队列的就可以遍历,难点是 把层和节点联系在一起,上一题是通过一个深度值,这个也可以这样,最笨的方法是queue 里面 append 节点和深度绑定, 有了节点和深度的绑定值 想做什么操作都可以
还有一种方式是先计算一下queue的长度,再设置一个count值,控制每一层的执行,拿满二叉树为例, 第一次 传入len(queue) = 0, 然后把左节点 右节点放进去, 第二轮迭代len(queue) = 2, 执行两次,queue 又添加了2*2=4个元素,第三轮len(queue)=4,。。。。
class Solution:
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
if not root:
return []
depth = 1
queue = [(root, depth)]
ret = []
cur = []
while queue:
count = len(queue)
cur.clear()
while count >0:
node,depth = queue.pop(0)
cur.append(node.val)
if node.left:
queue.append((node.left, depth+1))
if node.right:
queue.append((node.right, depth+1))
count -= 1
ret.append(cur.copy())
return ret
6 二叉树的层平均值 637
思路:和上面差不多 ,通过处理层框架!记住
python代码
class Solution:
def averageOfLevels(self, root):
"""
:type root: TreeNode
:rtype: List[float]
"""
queue = []
ret = []
queue.append(root)
while queue:
count = len(queue)
num = count
temp_sum = 0
while count > 0:
node = queue.pop(0)
temp_sum += node.val;
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
count -= 1
ret.append(temp_sum / num)
return ret