二叉树是每个节点最多有两个子树的树结构。它有五种基本形态:二叉树可以是空集;根可以有空的左子树或右子树;活着左、右子树皆为空。二叉树的结构很美妙,只有以下五种情况:
(图是@Begin to change的创作的!)
要理解递归算法,最好是从二叉树入手,很多一般递归的题目都可以从二叉树的递归中找到影子!!,可以说理解好二叉树是理解递归的前提(自己深有体会!!!!!)
首先从三种遍历方式开头:前序遍历,中序遍历,后序遍历。
前序遍历的顺序是先访问根节点,然后递归地先序遍历左子树,再递归地先序遍历右子树。
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
def preorder(root):
if root is None:
return
ans.append(root.val)
preorder(root.left)
preorder(root.right)
preorder(root)
return ans
C++:
/**
* 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:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ans;
function<void(TreeNode*)> preorder = [&](TreeNode* root) {
if (root == nullptr) {
return;
}
ans.push_back(root->val);
preorder(root->left);
preorder(root->right);
};
preorder(root);
return ans;
}
};
中序遍历首先访问左子树,然后访问根节点,最后访问右子树。中序遍历对于二叉搜索树尤其有用,因为它可以按升序访问所有节点。
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
def inorder(root):
if root is None:
return
inorder(root.left)
ans.append(root.val)
inorder(root.right)
inorder(root)
return ans
C++:
/**
* 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:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ans;
function<void(TreeNode*)> inorder = [&](TreeNode* root) {
if (root == nullptr) {
return;
}
inorder(root->left);
ans.push_back(root->val);
inorder(root->right);
};
inorder(root);
return ans;
}
};
后序遍历:1.访问左子树;2.访问右子树;3.完成该节点的左右子树的访问后,再访问该节点。即考察到一个节点后,将其暂存,遍历完左右子树后,再输出该节点的值。
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
def postorder(root):
if root is None:
return
postorder(root.left)
postorder(root.right)
ans.append(root.val)
postorder(root)
return ans
C++:
/**
* 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:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> ans;
function<void(TreeNode*)> postorder = [&](TreeNode* root) {
if (root == nullptr) {
return;
}
postorder(root->left);
postorder(root->right);
ans.push_back(root->val);
};
postorder(root);
return ans;
}
};
在看接下来的题目之前,我先讲一下我对于递归算法的理解,希望能对大家有帮助。
我认为,在看到一颗二叉树的时候,可能这颗二叉树有很多分支,很多节点,反正就是很复杂,很复杂的数。这个时候就把这一颗树抽象成一个根节点和它的左右儿子,也就是把n个节点的树抽象成只有三个节点的树,然后在这上面思考,这个时候就会变得简单很多。
接下来是几个题目:
题目要求从左到右顺序排列子节点的值,也就是说要先遍历左子树,再遍历右子树,并且要判断这个点是否是叶子节点 。我的主要思路是:分别将两个树的叶子节点用列表的形式拿出来,然后进行比较,看是否相等。(就按照上面的方法很好理解),我的代码:
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:
arr1, arr2 = [], []
# 这里其实可以写一个函数进行复用,减少代码量
def find1(node):
if not node.left and not node.right:
arr1.append(node.val)
if node.left:
find1(node.left)
if node.right:
find1(node.right)
def find2(node):
if not node.left and not node.right:
arr2.append(node.val)
if node.left:
find2(node.left)
if node.right:
find2(node.right)
find1(root1)
find2(root2)
return arr1 == arr2
C++
/**
* 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 leafSimilar(TreeNode* root1, TreeNode* root2) {
vector<int> ans1, ans2;
function<void(TreeNode*, vector<int>&)> find = [&](TreeNode* root, vector<int>& arr) {
if (root->left == root->right) {
arr.push_back(root->val);
}
if (root->left) {
find(root->left, arr);
}
if (root->right) {
find(root->right, arr);
}
};
find(root1, ans1);
find(root2, ans2);
if (ans1 == ans2) {
return true;
}
return false;
}
};
这个题目就是将所有节点的颜色记录下来然后去重就可以了,要实现上述操作,可以使用C++里面和Python的set容器。
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def numColor(self, root: TreeNode) -> int:
cnt = set()
def dfs(root):
if (root is None):
return
cnt.add(root.val)
dfs(root.left)
dfs(root.right)
dfs(root)
return len(cnt)
C++:
/**
* 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:
int numColor(TreeNode* root) {
set<int> cnt;
function<void(TreeNode*)> dfs = [&](TreeNode* root) {
if (root == nullptr) {
return;
}
cnt.insert(root->val);
dfs(root->left);
dfs(root->right);
};
dfs(root);
return cnt.size();
}
};
这个题一开始我有点不太会写,因为按照先遍历左子树,再遍历右子树的逻辑,那么就会同时加上左子树的叶子节点和右子树叶子节点的值,显然是不符合题意的。结果我发现我的点笨!!!只需要在判断左子树的时候改变ans的值就可以做到只保留左叶子节点的值了,如果右子树不为空的话,正常往下遍历就行了。
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
ans = 0
def dfs(root):
nonlocal ans
if root is None:
return
if root.left:
if root.left.left == root.left.right:
ans += root.left.val
else:
dfs(root.left)
if root.right:
dfs(root.right)
dfs(root)
return ans
C++:
/**
* 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:
int sumOfLeftLeaves(TreeNode* root) {
int ans = 0;
function<void(TreeNode*)> dfs = [&](TreeNode* root) {
if (root == nullptr) {
return;
}
if (root->left) {
if (root->left->left == root->left->right) {
ans += root->left->val;
}
else {
dfs(root->left);
}
}
if (root->right) {
dfs(root->right);
}
};
dfs(root);
return ans;
}
};
第一种方法:
这种方法比较好理解,就是用一个容器,将所有的节点的值通过遍历一遍二叉树后存储下来,然后进行排序去重操作,就能得到答案了。
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def findSecondMinimumValue(self, root: Optional[TreeNode]) -> int:
cnt = set()
def dfs(root):
if root is None:
return
cnt.add(root.val)
dfs(root.left)
dfs(root.right)
dfs(root)
if len(cnt) < 2:
return -1
# sort() 方法是对列表进行原地排序,它不会返回排序后的列表,而是返回 None
# sorted_list = list(cnt).sort()
sorted_list = list(cnt)
sorted_list.sort()
return sorted_list[1]
C++:
/**
* 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:
int findSecondMinimumValue(TreeNode* root) {
vector<int> cnt;
function<void(TreeNode*)> dfs = [&](TreeNode* root) {
if (root == nullptr) {
return;
}
cnt.push_back(root->val);
dfs(root->left);
dfs(root->right);
};
dfs(root);
sort(cnt.begin(), cnt.end());
cnt.erase(unique(cnt.begin(), cnt.end()), cnt.end());
if (cnt.size() < 2) {
return -1;
}
return cnt[1];
}
};
第二种方法:
定义一个变量来存储,但是说实话我感觉好像差不多~~~。
Python:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def findSecondMinimumValue(self, root: Optional[TreeNode]) -> int:
ans, route = -1, root.val #根节点是最小的
def dfs(root):
nonlocal ans
if root is None:
return
if ans != -1 and root.val >= ans:
return
if root.val > route:
ans = root.val
dfs(root.left)
dfs(root.right)
dfs(root)
return ans
C++:
/**
* 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:
int findSecondMinimumValue(TreeNode* root) {
int ans = -1;
int route = root->val;
function<void(TreeNode*)> dfs = [&](TreeNode* node) {
if (node == nullptr) {
return;
}
if (ans != -1 && node->val >= ans) {
return;
}
if (node->val > route) {
ans = node->val;
}
dfs(node->left);
dfs(node->right);
};
dfs(root);
return ans;
}
};
到这里就完结啦~~~~如果能把以上的题目都弄懂,那么对于二叉树有一定了解了,对于后面的学习会更加顺利,加油!!!!。