LeetCode刷题day34

简介: LeetCode刷题day34

今日刷题重点—二叉树的对称性

226. 翻转二叉树

翻转一棵二叉树

示例:

输入:
     4
   /   \
  2     7
 / \   / \
1   3 6   9
输出:
     4
   /   \
  7     2
 / \   / \
9   6 3   1

思路分析

反转二叉树:

7a55829528004e19bf80aedd274ca7dd.png

本质就是:把每一个结点的左右孩子互换一下,除了叶子结点所有的都要进行这样的操作.

方法一:递归法(以先序为例)

递归三要素


递归参数:每次要交换的根节点(交换的是其左右节点)

结束条件:当root为null时.

确定单层递归的逻辑

因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。


image.gif

参考代码1

//递归 
TreeNode* invertTree(TreeNode* root) {
  if(root==NULL) {
    return NULL;
  }
  swap(root->left,root->right);
  invertTree(root->left);
  invertTree(root->right);
  return root;
}

迭代法1(栈模拟)

用栈来模拟,因为递归的底层使用的就是栈.

参考代码2

//迭代法
TreeNode* invertTree(TreeNode* root) {
  if(root==NULL) {
    return NULL;
  }
  stack<TreeNode*> tab;
  tab.push(root);
  while(!tab.empty()) {
    TreeNode* node = tab.top();//中
    tab.pop();
    swap(node->left,node->right);
    if(node->left!=NULL) { //右
      tab.push(node->left);
    }
    if(node->right!=NULL) { //左
      tab.push(node->right);
    }
  }
  return root;
}

迭代法2(队列模拟)

用层次遍历的思路也是可以的.

参考代码3

TreeNode* invertTree(TreeNode* root) {
  if(root==NULL) {
    return NULL;
  }
  queue<TreeNode*> Q;
  Q.push(root);
  while(!Q.empty()) {
    int size = Q.size();
    for(int i = 0;i<size;i++){
      TreeNode* node = Q.front();
      Q.pop();
      swap(node->left,node->right);
      if(node->left){
        Q.push(node->left);
      }
      if(node->right){
        Q.push(node->right);
      }
    }
  }
  return root;
}

注意: 递归的中序遍历是不行的,因为使用递归的中序遍历,某些节点的左右孩子会翻转两次。

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

思路分析

首先要清楚对称二叉树比较的是哪两个节点,要比较的可不是左右节点!

对于是否对称,要比较的是根节点的左右子树是否可以反转. 理解了这一点就知道,其实我们要比较的是两棵树,所以在递归遍历过程中要同时遍历这两棵树.


那么如何进行比较呢?

如下图,我们只需要外侧和外侧进行对比,内侧和内侧进行比较即可.

e4ebe59202d3407c8492ce61f69e0e1a.png

方法一:递归

递归三部曲:

  • 确定参数和返回值:参数是左右子树,返回值是bool
  • 确定终止条件

首先要把两个节点为空的情况弄清楚! 否则后面比较数值的时候就会操作空指针了。


节点为空的情况有:


左节点为空,右节点不为空,不对称,return false

左不为空,右为空,不对称 return false

左右都为空,对称,返回true

左右节点不为空:


左右都不为空,比较节点数值,不相同就return false

剩下的一种情况就是,左右节点都不为空,而且其节点值相等.(我们后序在处理)


//先进行判空操作
  if(!left&&right || left&&!right) {
    return false;
  }
  if(!left&&!right) {
    return true;
  }
  //在进行 根节点值不同的情况
  if(left->val!=right->val) {
    return false;
  }
  • 确定单层递归的逻辑

单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。
//当前两个根节点的值相同,开始比较其树上的其他节点
  bool outSide = isCompare(left->left,right->right);
  bool inSide = isCompare(left->right,right->left);
  return outSide&&inSide;

参考代码1

//递归..
bool isCompare(TreeNode* left,TreeNode* right) {
  //先进行判空操作
  if(!left&&right || left&&!right) {
    return false;
  }
  if(!left&&!right) {
    return true;
  }
  //在进行 根节点值不同的情况
  if(left->val!=right->val) {
    return false;
  }
  //当前两个根节点的值相同,开始比较其树上的其他节点
  bool outSide = isCompare(left->left,right->right);
  bool inSide = isCompare(left->right,right->left);
  return outSide&&inSide;
}
bool isSymmetric(TreeNode* root) {
  if(root==NULL) {
    return true;
  }
  return isCompare(root->left,root->right);
}

方法二: 迭代法(使用队列)

可以使用队列来判断左右节点及其子树是否对称.

image.gif


参考代码2

bool isSymmetric(TreeNode* root) {
  if(root==NULL){
    return true;
  } 
  queue<TreeNode*> Q;
  Q.push(root->left);
  Q.push(root->right);
  while(!Q.empty()){
    TreeNode* node1 = Q.front();
    Q.pop();
    TreeNode* node2 = Q.front();
    Q.pop();
    //进行判空操作
    if(node1&&!node2 || !node1&&node2){
      return false;
    } 
    if(!node1&&!node2){//都为空说明是对称的,继续往下判断. 
      continue;
    }  
    if(node1->val!=node2->val){
      return false;
    }
    //说明此刻当前俩节点值相等,继续判断其树上的节点是否相等. 
    Q.push(node1->left);
    Q.push(node2->right);
    Q.push(node1->right);
    Q.push(node2->left); 
  }
  return true; 
}

方法三:使用栈

方法二,其实是把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,那么其实使用栈也是可以的。

参考代码3

bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        stack<TreeNode*> st; // 这里改成了栈
        st.push(root->left);
        st.push(root->right);
        while (!st.empty()) {
            TreeNode* leftNode = st.top(); st.pop();
            TreeNode* rightNode = st.top(); st.pop();
            if (!leftNode && !rightNode) {
                continue;
            }
            if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
                return false;
            }
            st.push(leftNode->left);
            st.push(rightNode->right);
            st.push(leftNode->right);
            st.push(rightNode->left);
        }
        return true;
    }

100. 相同的树

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:


image.jpeg

输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:

image.jpeg

输入:p = [1,2], q = [1,null,2]
输出:false

示例 3:


8fcab70d767c4ba4a8e260e0d4d3242a.jpg

输入:p = [1,2,1], q = [1,1,2]
输出:false

思路分析

上题是对称,这个题是相等,只需要修改下比较的两个节点的顺序即可.

也有递归,迭代(通过队列),迭代(通过栈)

参考代码1

bool isSameTree(TreeNode* left, TreeNode* right) {
  //先进行判空操作
  if(!left&&right || left&&!right) {
    return false;
  }
  if(!left&&!right) {
    return true;
  }
  //在进行 根节点值不同的情况
  if(left->val!=right->val) {
    return false;
  }
  //当前两个根节点的值相同,开始比较其树上的其他节点
  bool outSide = isSameTree(left->left,right->left);
  bool inSide = isSameTree(left->right,right->right);
  return outSide&&inSide;
}

参考代码2

bool isSameTree(TreeNode* left, TreeNode* right) {
  //先进行判空操作
  if(!left&&right || left&&!right) {
    return false;
  }
  if(!left&&!right) {
    return true;
  }
  //在进行 根节点值不同的情况
  if(left->val!=right->val) {
    return false;
  }
  //当前两个根节点的值相同,开始比较其树上的其他节点
  bool outSide = isSameTree(left->left,right->left);
  bool inSide = isSameTree(left->right,right->right);
  return outSide&&inSide;
}

572. 另一棵树的子树


给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。


二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。


示例 1:


9859b16b97a24393bf9b208b6420bb90.jpg

输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true

示例 2:

23f71dab30b14e5e91fd8520ede87da4.jpg

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false

思路分析

这个题判断两个树是否是树A和子树B的关系.

只需要遍历A上的每一个子树,判断和B是否相等,如果相等,则返回true.当A上的所有结点遍历完了还没找到则说明不存在,返回false.

参考代码

bool isSameTree(TreeNode* left, TreeNode* right) {
  //先进行判空操作
  if(!left&&right || left&&!right) {
    return false;
  }
  if(!left&&!right) {
    return true;
  }
  //在进行 根节点值不同的情况
  if(left->val!=right->val) {
    return false;
  }
  //当前两个根节点的值相同,开始比较其树上的其他节点
  bool outSide = isSameTree(left->left,right->left);
  bool inSide = isSameTree(left->right,right->right);
  return outSide&&inSide;
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
  if(root==NULL){//我 root树都已经遍历完了还没找到则直接返回false 
    return false;
  }
  //进行递归判断,只要有一个为真即为真. 
  return isSameTree(root,subRoot)||isSameTree(root->left,subRoot) ||isSameTree(root->right,subRoot);
}
相关文章
|
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