写在刚刚开始
从今天开始记录一些leetcode上的刷题记录和心得,小菜鸡也有成为大牛的梦想!从初级算法的树开始,之前的就不记录了,准备一个月刷到中级算法结束,加油!!
二叉树的最大深度
Question: 给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
Solution:
int maxDepth(TreeNode* root) {
if(!root) return 0;
return 1 + max(maxDepth(root -> left),maxDepth(root -> right));
}
主要利用递归的思想,如果节点为空则返回0,否则应给最后的结果加1,即这一层本身的高度,再进行递归调用即可找到最大深度的子树。
验证二叉搜索树
Question: 给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例1:
输入:
2
/ \
1 3
输出: true
示例2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
Solution1:
先贴网上看的解法:
bool isValidBST(TreeNode *root) {
return isValidBST(root, LONG_MIN, LONG_MAX);
}
bool isValidBST(TreeNode *root, long mn, long mx) {
if (!root) return true;
if (root->val <= mn || root->val >= mx) return false;
return isValidBST(root->left, mn, root->val) && isValidBST(root->right, root->val, mx);
}
利用了题目要求左<中<右这一规则,定义初始最小值和最大值,判断如果当前节点的值小于最小值或者大于最大值,则不满足二叉搜索树条件,其原理在于递归调用时,如果调用的是左子树,那么max值将被重置为根节点的值,这样保证了在接下来在左子树的遍历过程中,所有节点的值都必须要小于当前根节点。右子树同理。再换个说法,在判断某个节点是否满足二叉搜索树要求的条件时,我们需要要求这个节点的值大于所有他位于左子树部分的父节点的值,小于所有他位于右子树部分的父节点的值。再换个说法,每次往右递归的时候,把最小值限定在当前节点,后面只要有比这个小的,就不满足二叉搜索树条件,往左递归时同理。
接下来我来贴一下我的代码,大家笑一笑就好)
int maxnode(TreeNode* root) {
queue<TreeNode*> q;
if(root != nullptr)
q.push(root);
TreeNode *pmaxNode = root;
while(!q.empty()){
TreeNode* front = q.front();
if(pmaxNode->val < front->val){
pmaxNode = front;
}
q.pop();
if(front->left != nullptr)
q.push(front->left);
if(front->right != nullptr)
q.push(front->right);
}
return pmaxNode -> val;
}
int minnode(TreeNode* root) {
queue<TreeNode*> q;
if(root != nullptr)
q.push(root);
TreeNode *pminNode = root;
while(!q.empty()){
TreeNode* front = q.front();
if(pminNode->val > front->val){
pminNode = front;
}
q.pop();
if(front->left != nullptr)
q.push(front->left);
if(front->right != nullptr)
q.push(front->right);
}
return pminNode -> val;
}
bool isValidBST(TreeNode* root) {
if(!root) return true;
if(isValidBST(root -> left) && isValidBST(root -> right))
{
if(root -> left)
{
if(root -> val <= maxnode(root -> left)) return false;
}
if(root -> right)
{
if(root -> val >= minnode(root -> right)) return false;
}
return true;
}
return false;
}
跟别人比较后才知道自己有多菜…别人五行写完的代码我需要50行,差距真的很大!!我的思路就很笨了,非常笨,每次遍历到一个节点都判断他的右子树中的最小值,左子树的最大值。贴出来的目的不是分享代码,而是告诉自己要继续努力,写代码之前要找到最好的思路,不能直接用最蠢的思路,继续加油!
对称二叉树
Question:
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/ \
2 2
\ \
3 3
说明: 如果你可以运用递归和迭代两种方法解决这个问题,会很加分。
Solution:
- 递归解法:
我首先想到的是递归解法,定义一个同名函数,参数为左子树和右子树,通过递归调用这个函数来判断是否对称:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return isSymmetric(root -> left, root -> right);
}
bool isSymmetric(TreeNode* Left, TreeNode* Right)
{
if(!Left || !Right)
{
if(!Right && !Left) return true;
else return false;
}
if(Left -> val == Right -> val)
{
return isSymmetric(Left -> left, Right -> right) && isSymmetric(Right -> left, Left -> right);
}
return false;
}
值得一提的是,这里如果要求完全对称,即所有子树也是对称的,也可以用这个算法,只需要把递归调用改为:
return isSymmetric(Left -> left, Right -> right) && isSymmetric(Right -> left, Left -> right && isSymmetric(Right -> left, Right -> right) && isSymmetric(Right -> left, Left -> right);
- 迭代解法:
我的思路是左子树先加入左边节点,右子树先加入右边节点,存放在两个队列中,然后出队列比较,再按顺序分别将子节点加入两个队列,这里是网上找的代码,思路基本一致:
bool isSymmetric(TreeNode *root) {
if (!root) return true;
queue<TreeNode*> q1, q2;
q1.push(root->left);
q2.push(root->right);
while (!q1.empty() && !q2.empty()) {
TreeNode *node1 = q1.front();
TreeNode *node2 = q2.front();
q1.pop();
q2.pop();
if((node1 && !node2) || (!node1 && node2)) return false;
if (node1) {
if (node1->val != node2->val) return false;
q1.push(node1->left);
q1.push(node1->right);
q2.push(node2->right);
q2.push(node2->left);
}
}
return true;
}
二叉树的层次遍历
Question:
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
Solution:
层序遍历需要用到队列,因为这里要求输出的是按每一层输出,所以我的初始想法是使用两个队列,初始队列元素为root,每次遍历都让队列中的所有元素出队列并把子元素加入另外一个队列,另外一个队列随后采用相同算法,但子元素将加入第一个队列,这样就实现了分层输出的层序遍历。
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
vector<int> temp;
if(!root) return result;
queue<TreeNode*> q1,q2;
q1.push(root);
while(!q1.empty() || !q2.empty())
{
if(!q1.empty())
{
do
{
TreeNode *mynode = q1.front();
temp.push_back(mynode -> val);
if(mynode -> left) q2.push(mynode -> left);
if(mynode -> right) q2.push(mynode -> right);
q1.pop();
}while(!q1.empty());
}
else
{
do
{
TreeNode *mynode = q2.front();
temp.push_back(mynode -> val);
if(mynode -> left) q1.push(mynode -> left);
if(mynode -> right) q1.push(mynode -> right);
q2.pop();
}while(!q2.empty());
}
result.push_back(temp);
temp.clear();
}
return result;
}
这里应该也是可以只用一个队列的,加一个flag应该就可以啦,这道题还挺简单的,就不多说了!^ ^(或者说这些题都不难只是我菜–
将有序数组转换为二叉搜索树
Question:
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
Solution:
我的思路是利用递归的思想,把数组从中间切开,中间的元素就是根节点,分开的数组又可以分别调用sortedArrayToBst函数来生成子搜索树。
TreeNode* sortedArrayToBST(vector<int>& nums) {
if(!nums.size()) return NULL;
TreeNode *root = new TreeNode(nums[nums.size()/2]);
vector<int> num1,num2;
num1.insert(num1.begin(),nums.begin(),nums.begin() + nums.size()/2);
root -> left = sortedArrayToBST(num1);
num2.insert(num2.begin(),nums.begin() + nums.size()/2 + 1, nums.end());
root -> right = sortedArrayToBST(num2);
return root;
}
这里还想提一些小的tips:
- 关于初始化
初始化树的时候要调用构造函数来初始化其初值,不能先初始化然后直接赋值 - 关于vector
vectord 的 insert函数是从开头的元素后一个到最后一个元素前一个插入,这个要注意。
写在后面
看一下时间,今天是2019.6.12,花了大概4-5个小时做完了树的这六道题,感觉收获还是有的,不过这只是刚刚开始,继续加油啊~~~~做题最大的感受就是自己的代码思路还是差的多,不能一下子想出来最好的算法,还有就是大一时因为栈队列云云没学好,导致都不敢用,在此立下flag,以后能用则用!
这个月刷leetcode的目的是准备保研夏令营,其实这也是我目前读研的初衷把,感觉自己的本事还是不够扎实,希望在研究生阶段能够沉下心,真正能肚子里有东西,才能游刃有余,不惧未来~
Believe In Your Heart!