LeetCode刷题day15

简介: LeetCode刷题day15

144. 二叉树的前序遍历

94. 二叉树的中序遍历

145. 二叉树的后序遍历

思路分析:

递归和迭代两种方法都可进行处理

方法一:递归

参考代码

//前序
void preorder(TreeNode* T) {
  if(T) {
    V.push_back(T->val);
    preorder(T->left);
    preorder(T->right);
  }
}
//中序
void inorder(TreeNode* T) {
  if(T) { 
    inorder(T->left);
    V.push_back(T->val);
    inorder(T->right);
  }
}
//后序
void postorder(TreeNode* T) {
  if(T) {
    postorder(T->left);
    postorder(T->right);
    V.push_back(T->val);
  }
}
vector<int> V;
vector<int> xxxorderTraversal(TreeNode* root) {
  xxxorder(root);
  return V;
}

方法二:迭代

本质上是在模拟递归,因为在递归的过程中使用了系统栈,所以在迭代的解法中常用Stack来模拟系统栈。


以前序遍历为例


首先我们应该创建一个Stack用来存放节点,首先我们想要打印根节点的数据,此时Stack里面的内容为空,所以我们优先将头结点加入Stack,然后打印。

之后我们应该先打印左子树,然后右子树。所以先加入Stack的就是右子树,然后左子树。

此时你能得到的流程如下:

f27ab13cf7f749fc9cb9217d84ca334d.png

参考代码2

//迭代做法. 
vector<int> preorderTraversal(TreeNode* root) { 
  if(root==null){
    return {};
  }
  vector<int> V;
  TreeNode* cur = root; 
  stack<TreeNode*> S;
  S.push(root);   
  while(!stack.empty()){
    TreeNode* node = S.top();
    S.pop();
    V.push_back(node->val);//通过改变该语句的顺序,来决定是先序,中序和后序..
    if(node->right != NULL){
      S.push(node->right);
    } 
    if(node->left!=NULL){
      S.push(node->left);
    }
  }
  return V;
}

102. 二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

示例:


二叉树:[3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
返回其层序遍历结果:
[
  [3],
  [9,20],
  [15,7]
]

思路分析:

参考 BFS的使用场景总结

参考代码

#include<bits/stdc++.h>
using namespace std;
https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ 
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) {}
};
vector<vector<int>> levelOrder(TreeNode* root) {
  vector<vector<int>> V;
  queue<TreeNode*> Q;
  if(root==NULL){
    return {};
  }
  Q.push(root);
  while(!Q.empty()){
    int n  = Q.size();//计算当前层元素的个数 
    vector<int> v;
    for(int i = 0;i <n;i++){//将当前层元素弹出放到v中. 
      TreeNode* node = Q.front();
      Q.pop();
      v.push_back(node->val);
      if(node->left){
        Q.push(node->left);
      }
      if(node->right){
        Q.push(node->right);
      }     
    }
    V.push_back(v); 
  }
  return V;
}

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3 。

参考代码

int maxDepth(TreeNode* root) {
  int m,n;
  if(root){
    return 0;
  }else{
    m = maxDepth(root->left);//递归计算左子树深度 
    n = maxDepth(root->right);//递归计算右子树深度 
    if(m>n){
      return m+1;//返回左右子树的最大值+1 
    }else{
      return n+1;
    }
  }
}

101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [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


方法一:递归


根据题目的描述,镜像对称,就是左右两边相等,也就是左子树和右子树是相当的。

注意这句话,左子树和右子相等,也就是说要递归的比较左子树和右子树。


我们将根节点的左子树记做 left,右子树记做 right。比较 left 是否等于 right,不等的话直接返回就可以了。

如果相当,比较 left 的左节点和 right 的右节点,再比较 left 的右节点和 right 的左节点

比如看下面这两个子树(他们分别是根节点的左子树和右子树),能观察到这么一个规律:


左子树 2 的左孩子 == 右子树 2 的右孩子

左子树 2 的右孩子 == 右子树 2 的左孩子


   2         2
   / \       / \
  3   4     4   3
 / \ / \   / \ / \
8  7 6  5 5  6 7  8


根据上面信息可以总结出递归函数的两个条件:

终止条件:

  • left 和 right 不等,或者 left 和 right 都为空
  • 递归的比较 left.left 和 right.right,递归比较 left.right 和 right.left
    动态图如下:

19678d9f073e49b18d089f1ef114cb0c.gif


时间复杂度:O(n),因为要遍历 n 个节点

空间复杂度是 O(n),空间复杂度是递归的深度,也就是跟树高度有关,最坏情况下树变成一个链表结构,高度是n。

参考代码:


#include<bits/stdc++.h>
using namespace std;
//https://leetcode-cn.com/problems/symmetric-tree/
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) {}
};
// 递归+dfs 
bool dfs(TreeNode* left,TreeNode* right){
  //递归终止的条件
  if(left==NULL&&right==NULL){
    return true;//肯定对称 
  } 
  if(left==NULL||right==NULL){
    return false;
  } 
  if(left->val!=right->val){
    return false;
  } 
  return dfs(left->left,right->right)&&dfs(left->right,right->left);
}
bool isSymmetric(TreeNode* root) {
  if(root==NULL){
    return true;
  }
  //调用递归函数,比较左节点和右节点
  return dfs(root->left,root->right); 
}
int main()
{
  return 0;
}

方法二:迭代

回想下递归的做法:

当两个子树的根节点相等时,就比较:左子树的 left 和 右子树的 right.

现在我们改用队列来实现,思路如下:


首先从队列中拿出两个节点(left 和 right)比较

将 left 的 left 节点和 right 的 right 节点放入队列

将 left 的 right 节点和 right 的 left 节点放入队列

时间复杂度是O(n),空间复杂度是 O(n)


image.gif

参考代码:

#include<bits/stdc++.h>
using namespace std;
//https://leetcode-cn.com/problems/symmetric-tree/
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) {}
};
// 迭代 
bool isSymmetric(TreeNode* root) {
  if(root==NULL || (root->left==NULL && root->right==NULL)){
    return true;
  } 
  //用队列保存左右节点
  queue<TreeNode*> Q;
  Q.push(root->left);
  Q.push(root->right);
  while(!Q.empty()){
    TreeNode* left = Q.front();
    Q.pop();
    TreeNode *right = Q.front();
    Q.pop();
    if(left==NULL&&right==NULL){
//      return true;
      continue;//进行下一组节点的判断 
    }
    if(left==NULL||right==NULL){
      return false;
    }
    if(left->val!=right->val){
      return false;
    }
    //将左节点的左孩子,右节点的右孩子放入队列.
    Q.push(left->left);
    Q.push(right->right); 
    //将左节点的右孩子,右节点的左孩子放入队列 
    Q.push(left->right);
    Q.push(right->left);
  }
  return true;
}
相关文章
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
57 6
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
52 4
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
118 2
|
26天前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
21 1
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
3月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
64 7
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
54 5
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 30. 包含min函数的栈
本文提供了实现一个包含min函数的栈的Python代码,确保min、push和pop操作的时间复杂度为O(1)。
28 4
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
Leetcode题目"剑指 Offer 21. 调整数组顺序使奇数位于偶数前面"的两种Python解决方案,一种是使用双端队列调整数组顺序,另一种是使用双指针法将奇数移到数组前半部分,偶数移到后半部分。
28 4