前言

所有题目均来自力扣题库中的hot 100,之所以要记录在这里,只是方便后续复习

98.验证二叉搜索树

题目:
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:

输入:root = [2,1,3]
输出:true
示例 2:
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
提示:
树中节点数目范围在[1, 104] 内
-231 <= Node.val <= 231 - 1
解题思路:
【递归】根据二叉搜索树的性质:我们要先判断左子树值小于根节点值,右子树值大于根节点值,符合条件的话我们要在判断左子数是否是搜索二叉树,右子树是否为搜索二叉树,因为判断方式一样,这就很容易联想到递归;那递归的中止条件是什么呢?当节点为空时,直接放回True即可;那我们在递归的时候每个根节点的值是会变的,其左子树 和 右子树值的范围也会跟着改变,所以要把这个范围当作参数传入递归函数,当递归左子数时要更新最大值为根节点值,递归右子树时要更新最小值为根节点值
代码(python):

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):def isValidBST(self, root):""":type root: TreeNode:rtype: bool"""# 定义初始的最新小值 和 最大值,注意不是int类型最值了,是正负无穷low = float("-inf")high = float("inf")# 调用递归方法return self.test(root, low, high)def  test(self, root, low, high):#如果当前节点为空,直接返回True即可if root is None:return True# 如果当前节点 值超过了 最小值 和 最大值的范围,直接返回Falseif root.val >= high or root.val <= low:return False# 递归验证左子数和右子树是否为搜索二叉树# 注意要更新最小值或最大值的范围 左子数的最大值变成节点值  右子树的最小值变成节点值return self.test(root.left, low, root.val) and self.test(root.right, root.val , high)

代码(java):

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public boolean isValidBST(TreeNode root) {ArrayList<Integer> values = new ArrayList<>();zhongXu(root, values);return isSorted(values);}public void zhongXu(TreeNode root, ArrayList<Integer> values){if(root == null){return;}zhongXu(root.left, values);values.add(root.val);zhongXu(root.right, values);}public boolean isSorted(ArrayList<Integer> values){for(int i = 0; i < values.size() - 1; i++){if (values.get(i) >= values.get(i + 1)){return false;}}return true;}
}

知识点:

  • python中,可以用float(“inf”)和float(“-inf”)表示正负无穷,而sys.maxsize和-sys.maxsize - 1表示最大int值和最小int值
  • java中,可以用Long.MAX_VALUE和Long.MIN_VALUE表示Long类型的最大最小值,而Integer.MAX_VALUE和Integer.MIN_VALUE表示int类型的最大最小值

原题链接:验证二叉搜索树

102.二叉树的层序遍历

题目:
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:
输入:root = [1]
输出:[[1]]
示例 3:
输入:root = []
输出:[]
解题思路:
【队列】首先想到的思路是先用节点集合把一层的节点存储起来,然后将一层节点值取出来组成一个集合并添加到结果集合中,再把这个集合里的节点替换成下一层节点,可是这样要频繁删除节点集合的值,进一步优化我们可以用队列存储节点,这样边将本层节点依次出队列将值放到集合中,边将该节点的子节点入队列,那这种怎么知道哪些节点是本层的,哪些节点是下一层的呢?可以在每层出队列开始时(此时下一层节点还未入列队)计算一下队列长度,只按这个长度进行出队列,这样就都是本层节点了
代码(python):

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):def levelOrder(self, root):""":type root: TreeNode:rtype: List[List[int]]"""results = []self.test(root, results, 0)return resultsdef test(self, root, results, level):if root is None:returnif level >= len(results):results.append([root.val])else:results[level].append(root.val)self.test(root.left, results, level + 1)self.test(root.right, results, level + 1)

代码(java):

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {//定义 结果集合ArrayList<List<Integer>> result = new ArrayList<>();// 如果当前节点为空,返回空集合即可if(root == null){return result;}//定义队列,用来存放每层的节点Queue<TreeNode> myQueue = new LinkedList<>();//先把根节点放入队列中myQueue.offer(root);//从队列中取值,直到队列为空while(myQueue.isEmpty() == false){// 先计算一下当前队列的长度,即计算一下这一层有多少个节点,用来作层与层之间的分割int curSize = myQueue.size();// 定义当前集合ArrayList<Integer> curList = new ArrayList<>();// 把这一层的节点依次拿出,并将节点的值添加到当前集合中,再将左节点和右节点添加都队列中用于下一层的遍历,注意判断左右节点是否为空for(int i = 0; i < curSize; i ++){TreeNode curNode = myQueue.poll();curList.add(curNode.val);if (curNode.left != null){myQueue.offer(curNode.left);}if (curNode.right != null){myQueue.offer(curNode.right);}}// 将当前集合添加到结果集合中result.add(curList);}return result;}
}

知识点:

  • java中可以用LinkedList当作队列,linkedlist.offer(val)表示入队列,linkedlist.poll()表示出队列,linkedlist.isEmpty()判断对列是否为空
  • python中可以用Queue()定义队列,但是需要导报from queue import Queue,入队列put(val),出队列get()

原题链接:二叉树的层序遍历

105.从前序与中序遍历序列构造二叉树

题目:
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
示例 2:
输入: preorder = [-1], inorder = [-1]
输出: [-1]
解题思路:
【递归】二叉树的题可以先考虑递归,我们先确定根节点,然后确定左子数和右子树有哪些节点,再用递归去构造左右子树即可;怎么确定根节点?根据先序遍历的顺序:根-左-右,先序遍历序列第一个值即为根节点的值;怎么确定左子数和右子树有哪些呢?根据中序遍历的顺序:左-根-右,我们在中序遍历序列中找到根节点,那他左边的就是左子数的节点,右边的就是右子树的节点,我们可以计算出左右子树的节点个数,根据左右子树的个数我们就可以把先序和中序序列进行有效的切分并进行左右子树的递归,与其进行序列的切分倒不如用左右边界值控制有效范围,减少时间复杂度;那递归的中止条件是什么呢?即左右子树个数为0的即左右边界值无效的情况,返回空节点即可
代码(python):

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):inorderIndex = {}def buildTree(self, preorder, inorder):""":type preorder: List[int]:type inorder: List[int]:rtype: TreeNode"""if preorder is None or len(preorder) == 0:return Noneself.getInorderIndex(inorder)return self.myBuildTree(preorder, inorder, 0, len(preorder) - 1, 0, len(inorder) - 1)def myBuildTree(self, preorder, inorder, preorder_left, preorder_right, inorder_left, inorder_right):"""递归方法通过先序遍历的第一个位置确定出根节点通过根节点在中序遍历中的位置,左侧部分为左子树,右侧部分为右子树分别将左子树和右子树通过递归的方式进行构造数,并赋给根节点的左右节点"""#如果先序遍历列表的左边界大于右边界,直接返回if preorder_left > preorder_right:return#如果先序遍历列表的左边界等于右边界,说明只有一个节点,该节点没有子节点,直接新建节点赋值返回if preorder_left == preorder_right:return TreeNode(preorder[preorder_left])#前序遍历的第一个值即左边界值就是 根节点,创建根节点root = TreeNode(preorder[preorder_left])#通过根节点的值在中序遍历中找到该位置index = self.inorderIndex[preorder[preorder_left]]#计算出左子树的节点个数left_number = index - inorder_left#递归得到左子树并赋给根节点  通过左子树的个数得到左子树前序遍历的边界范围,通过根节点在中序遍历的位置得到左子树的中序遍历的边界范围root.left = self.myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + left_number, inorder_left, index - 1)#递归得到右子树并赋给根节点  通过左子树的个数得到右子树前序遍历的边界范围,通过根节点在中序遍历的位置得到右子树的中序遍历的边界范围root.right = self.myBuildTree(preorder, inorder, preorder_left + left_number + 1, preorder_right,index + 1, inorder_right)return rootdef getInorderIndex(self, inorder):"""获取到中序遍历数组的索引与节点的对应关系 --节点:索引 放到属性字典里"""for i in range(0, len(inorder)):self.inorderIndex[inorder[i]] = i

代码(java):

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public TreeNode buildTree(int[] preorder, int[] inorder) {//调用递归函数return test(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);}public TreeNode test(int[] preorder, int pl, int pr, int[] inorder, int il, int ir){// 当先序遍历的左边界值大于右边界 或 中序遍历的左边界大于右边界,说明当前树点为空if(pl > pr || il > ir){return null;}// 当先序遍历或中序遍历的左边界和右边界相等,说明,当前树只有一个节点,直接构造一个节点返回即可if(pl == pr || il == ir ){return new TreeNode(preorder[pl]);}//先序遍历有效范围第一位即根节点  根据先序遍历的性质int rootValue = preorder[pl];TreeNode root = new TreeNode(rootValue);// 在中序遍历有效位范围内找到根节点,int rootIndex = il;for (int i = il; i <= ir; i ++){if(inorder[i] == rootValue){rootIndex = i;break;}}//定义左右子树的节点个数   因为中序遍历有效范围内根节点左边的节点都是左子数,右边的节点都是右子树int leftNum = rootIndex - il;int rightNum = ir - rootIndex;// 通过递归的方式构造左右子树并赋给根节点 通过控制有效范围达到传递子树的先序遍历和中序遍历效果root.left = test(preorder, pl + 1, pl + leftNum, inorder, il, rootIndex - 1);root.right = test(preorder, pl + leftNum + 1, pl + leftNum + rightNum, inorder, rootIndex + 1, ir);return root;}
}

知识点:

原题链接:从前序与中序遍历序列构造二叉树

114.二叉树展开为链表

题目:
给你二叉树的根结点 root ,请你将它展开为一个单链表:

展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1:

输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]
示例 2:

输入:root = []
输出:[]
示例 3:

输入:root = [0]
输出:[0]
解题思路:
【链表遍历】由于和先序遍历顺序相同,我们可以先序遍历二叉树,将节点存放在列表里,然后将他们拼成链表,但这样空间复杂度为On;要想空间复制度为O1,需要原地操作,将其展开为单链表,其实就是将所有左子数插入右子树对应的位置,我们可以遍历二叉树,如果有左子树,就让其插入右子树中;怎么插入右子树呢,我们先将右子树挂在左子数上,挂在哪里呢?根据先序遍历的顺序,右子树的前一个节点应该是左子数的最右节点,就挂在最右节点上,然后将左子数移到原右子树的位置,这样就完成了左子数的插入,注意的是原左子数要置为空
代码(python):

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):nodes = []def flatten(self, root):""":type root: TreeNode:rtype: None Do not return anything, modify root in-place instead."""if root is None:return Noneself.pre(root)head = self.nodes[0]tail = headfor i in range(0, len(self.nodes) - 1):tail.left = Nonetail.right = self.nodes[i + 1]tail = tail.rightreturn headdef pre(self, root):if root is None:returnself.nodes.append(root)self.pre(root.left)self.pre(root.right)

代码(java):

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left; *     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public void flatten(TreeNode root) {//定义索引节点TreeNode cur  = root;// 遍历怎个二叉树while(cur != null){//如果存在左子数if (cur.left != null){//将其左子树存起来TreeNode next = cur.left;// 找到左子树的最右节点 即右子树的前节点TreeNode pre = next;while (pre.right != null){pre = pre.right;}//将 右子树挂在前节点上(也是左子树)pre.right = cur.right;// 将当前节点的左子数 置为空cur.left = null;// 将当前节点右子树 置为 原来存的左子树cur.right = next;}// 滑动索引节点 (包括左子数处理完的情况 与 左子数为空不需要处理的情况)cur = cur.right;}}
}

知识点:

原题链接:二叉树展开为链表

236.二叉树的最近公共祖先

题目:
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1

解题思路:
【链表遍历】我们可以从两个节点向上查找其到根节点路径,第一个相交的节点便是最近公共祖先;但是向上查找需要知道各个节点的父节点怎么办?我们可以先遍历一遍二叉树,通过字典(子节点-父节点)的存储各个节点的父节点;这样我们可以先用列表存储一个节点路径(要保证有序,不能用hash结构),在寻找第二个节点的路径时判断是否在第一个路径中,若在则该节点就是相交节点即结果值
代码(python):

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution(object):def lowestCommonAncestor(self, root, p, q):""":type root: TreeNode:type p: TreeNode:type q: TreeNode:rtype: TreeNode"""# 定义字典,用来存储每个节点的父节点parents = dict()self.get_parents(root, parents)# 根据字典,从p节点开始到根节点,依次把父节点放入列表中p_list = list()while p:p_list.append(p)p = parents.get(p, None)# 根据字典,从q节点开始遍历其父节点,第一个在列表中节点就是最近公共祖先while q not in p_list:q = parents.get(q, None)return qdef get_parents(self, root, parents):# 如果节点为空 直接返回if root is None:return# 如果有左节点,将左节点的父节点放入字典中if root.left:parents[root.left] =  root# 如果有右节点,将右节点的父节点放入字典中if root.right:parents[root.right] = root# 递归寻找出左右子数的各个节点的父节点self.get_parents(root.left, parents)self.get_parents(root.right, parents)

代码(java):

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode(int x) { val = x; }* }*/
class Solution {public HashMap<Integer, TreeNode> parents = new HashMap<>();public void dfs(TreeNode root){if (root.left != null){this.parents.put(root.left.val, root);dfs(root.left);}if (root.right != null){this.parents.put(root.right.val, root);dfs(root.right);}}public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {dfs(root);ArrayList<Integer> pList = new ArrayList<>();while(p.val != root.val){pList.add(p.val);p = this.parents.get(p.val);}pList.add(p.val);while(q.val != root.val){if (pList.contains(q.val)){return q;}q = this.parents.get(q.val);}return root;}
}

知识点:

  • python中可以用dict.get(key, default),从字典中获取值,若没有该键则返回default值

原题链接:二叉树的最近公共祖先

刷题记录8---验证二叉搜索树+二叉树的层序遍历+从前序与中序遍历序列构造二叉树+二叉树展开为链表+二叉树的最近公共祖先相关推荐

  1. LeetCode 426. 将二叉搜索树转化为排序的双向链表(BST中序循环遍历)

    文章目录 1. 题目 2. 解题 1. 题目 将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表 . 对于双向循环列表,你可以将左右孩子指针作为双向循环链表的前驱和后继指针,第一个节点的前驱是最 ...

  2. leetcode230. 二叉搜索树中第K小的元素(中序遍历)

    给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素.说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数.示例 1:输入: root = [3, ...

  3. LeetCode 230. 二叉搜索树中第K小的元素(中序遍历)

    文章目录 1. 题目信息 2. 解题 2.1 中序递归 2.2 中序循环写法 1. 题目信息 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明: 你可以 ...

  4. LeetCode 98. 验证二叉搜索树 思考分析

    题目 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二 ...

  5. leetcode98验证二叉搜索树刷题打卡

    98. 验证二叉搜索树 题目描述 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树. 有效 二叉搜索树定义如下: 节点的左子树只包含 小于 当前节点的数. 节点的右子树只包含 大于 ...

  6. LeetCode 之 JavaScript 解答第98题 —— 验证二叉搜索树(Validate Binary Search Tree)

    Time:2019/4/24 Title: Vaildata Binary Search Tree Difficulty: Medium Author: 小鹿 题目:Vaildata Binary S ...

  7. [Leedcode][JAVA][第98题][验证二叉搜索树]

    [问题描述][第98题][验证二叉搜索树][中等] 给定一个二叉树,判断其是否是一个有效的二叉搜索树.假设一个二叉搜索树具有如下特征:节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节 ...

  8. Leetcode 98:验证二叉搜索树

    Leetcode 98:验证二叉搜索树 题目描述 我的解法:非递归的中序遍历 其它解法1:非递归的中序遍历,用LONG_MIN规避树的val等于INT_MIN的情况 其他解法2:递归的中序遍历思想 其 ...

  9. [CareerCup] 4.5 Validate Binary Search Tree 验证二叉搜索树

    4.5 Implement a function to check if a binary tree is a binary search tree. LeetCode上的原题,请参见我之前的博客Va ...

最新文章

  1. 比Momentum更快:揭开Nesterov Accelerated Gradient的真面目NAG 梯度下降
  2. 嵌入式CNN检测网络--LCDet
  3. 零售行业O2O盛行 或成黑客窃取数据目标
  4. 倒置 mysql_SQL Server中的行列倒置技巧
  5. Java web学习(一)Servlet简介
  6. k8s:koolshare软路由安装及k8s基本环境配置
  7. Qt QML 实现Android相册展示
  8. 如何写出吸引HR的软件测试简历
  9. 词频统计及其效能分析
  10. visio防火墙可以连接什么_分享一款网工必备网络拓扑图绘制工具Visio以及大量厂商图标库...
  11. 知识付费与内容付费的区别
  12. 开篇:为什么开始写博客
  13. 最全Web前端面试题汇总 笔试题汇总 JavaScript HTML css
  14. D - Silver Cow Party J - Invitation Cards 最短路
  15. pdf合并成一个pdf软件?能合并pdf的软件?
  16. js根据后缀名判断文件的类型
  17. 网站建设和网站运营需要注意什么重要因素
  18. c++ 解析eps文件
  19. 智能名片有哪些功能才是适合企业销售的?
  20. 椭圆切线方程公式的推导过程

热门文章

  1. word尾注后加入致谢(mac版)
  2. 如何实现Siri中的波纹动画
  3. 服务器的存储系统中做镜像,缓存镜像技术在存储中的应用
  4. windows api控制鼠标移动的快慢
  5. 韩php,韩国php相册程序photogallery2使用教程
  6. 不下载英语包 Vista照样可以玩梦幻桌面
  7. p2p云服务是什么_先锋p2p云服务器端(XfServer)下载 v8.0
  8. DESC_MOL-DDIE模型复现记录(发现问题)
  9. 鼓励软件产业和集成电路产业发展的若干政策(2000)
  10. pytorch每日一学10(torch.set_printoptions())更改打印设置