Leetcode学习笔记(5)
之前断了一段时间没做Leetcode,深感愧疚,重新续上
题目1 ID104
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
我的解答:
使用递归求二叉树的最大深度,想要求根节点的最大深度,需要求其左右两个节点中更大的深度+1,想要求左右两个节点的深度也是如此,代码如下:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ int maxDepth(struct TreeNode* root){ int leftDepth,rightDepth; if(root==NULL){ return 0; }else{ leftDepth=maxDepth(root->left); rightDepth=maxDepth(root->right); return leftDepth>rightDepth?leftDepth+1:rightDepth+1; } }
题目2 ID102
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
我的解答:
在这里没有采用逐层遍历,而是使用的dfs深度优先遍历的方式,将每一个节点的值放入相对应的列表里,使用level判断层数,levels储存得到的所有节点值,树的最高层次即len(levels),添加新列表储存节点值的判断是由当前树的最高层次和当前节点所在层数比较得到的,如果当前节点所在层数大于树的最高层次,证明需要添加一个新列表储存值。get函数递归非空的孩子节点,参数是node当前节点和level当前节点层数:
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: levels=[] if not root: return levels def get(node,level): if len(levels)==level: levels.append([]) levels[level].append(node.val) if node.left: get(node.left,level+1) if node.right: get(node.right,level+1) get(root,0) return levels
题目3 ID100
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1
/ \ / \
2 3 2 3
[1,2,3], [1,2,3]
输出: true
示例 2:
输入: 1 1
/ \
2 2
[1,2], [1,null,2]
输出: false
示例 3:
输入: 1 1
/ \ / \
2 1 1 2
[1,2,1], [1,1,2]
输出: false
我的解答:
可以想到采用递归判断的方式,如果两个节点都是空的话,就返回true,其中一个是空的话,就返回false,然后再判断两个非空节点的val值是否相同,不同的话返回flase,递归判断两棵树的孩子节点
Python3代码:
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: if not p and not q: return True if not p or not q: return False if p.val!=q.val: return False return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right)
C语言代码:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ bool isSameTree(struct TreeNode* p, struct TreeNode* q){ if(p==NULL&&q==NULL){ return true; } if(p==NULL||q==NULL){ return false; } if(p->val!=q->val){ return false; } return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right); }
题目4 ID101
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [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
说明:
如果你可以运用递归和迭代两种方法解决这个问题,会很加分。
我的解答:
评论区里面的老哥说的很好,其实主要是理解递归的思想:
我们首先判断根节点是否为空,非空的时候再判断其左右子树是否对称,左树的左孩子需要和右树的右孩子对称,左树的右孩子需要和右树的左孩子对称,先比较当前节点的值是否相同,再递归判断其左右孩子的对称情况,写写就知道了:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ bool check(struct TreeNode* node1,struct TreeNode* node2){ if(node1==NULL&&node2==NULL){ return true; } if(node1==NULL||node2==NULL){ return false; } if(node1->val!=node2->val){ return false; } return node1->val==node2->val&&check(node1->left,node2->right)&&check(node1->right,node2->left); } bool isSymmetric(struct TreeNode* root){ if(root==NULL){ return true; } return check(root->left,root->right); }
题目5 ID107
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其自底向上的层次遍历为:
[
[15,7],
[9,20],
[3]
]
我的解答:
与ID100题相同,最后只需要将列表反转,这里使用python的切片操作,levels[::-1],表示从,后往前取,每次步进值为1,达到了反转列表的效果。
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrderBottom(self, root: TreeNode) -> List[List[int]]: levels=[] if not root: return levels def get_node(node,level): if len(levels)==level: levels.append([]) levels[level].append(node.val) if node.left: get_node(node.left,level+1) if node.right: get_node(node.right,level+1) get_node(root,0) return levels[::-1]
题目6 ID111
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最小深度 2.
我的解答:
最开始的代码是这样的:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ int min_num(int a,int b){ return a<b?a:b; } int min(struct TreeNode* node,int level){ if(node==NULL){ return 9999; } if(node->left==NULL&&node->right==NULL){ return level+1; }else{ return min_num(min(node->left,level+1),min(node->right,level+1)); } } int minDepth(struct TreeNode* root){ if(root==NULL){ return 0; } return min(root,0); }
如果根节点为空,那么我们就返回0,否则进入自己构造的min函数,因为题目给出的函数minDepth函数没有给出树的层次,为了方便重新创建了min函数,传入参数为当前节点和当前节点所在层数,如果这个节点是NULL的话,返回9999,也就是当前节点为空节点,加上很大的数,使其不能够成为最短的。这是为了避免出现[1,2]这种情况,叶子节点并不是根节点,所以[1,2]对应的答案是2,而不是1。接着判断当前节点是否是叶子节点,是的话返回层数+1,不是的话继续递归当前节点的叶子节点,取其中较小值。
但是如return 9999,以及重新定义min函数,这些地方处理不是很好。测试案例过大的话还是会出错,重新整理思路为:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ int min_num(int a,int b){ return a<b?a:b; } int minDepth(struct TreeNode* root){ if(root==NULL){ return 0; } if(root->left==NULL&&root->right==NULL){ return 1; } int minleft=minDepth(root->left); int minright=minDepth(root->right); if(root->left==NULL||root->right==NULL){ return minleft+minright+1; } return min_num(minleft,minright)+1; }
在寻找树的根到叶子结点一共有四种情况,1,当前节点为null,返回0;2,当前节点的左孩子和右孩子都为null,这符合了叶子节点的定义,返回1,;3,当前节点的左孩子和右孩子中有一个是NULL,空节点的值为0,对结果不造成影响,不需要判断是左孩子和右孩子中的哪一个,直接返回 左孩子的深度+右孩子的深度+1即可;4,两个节点都不为空,正常处理,返回其较小的那一个深度+1。
题目7 ID面试题04.02
给定一个有序整数数组,元素各不相同且按升序排列,编写一个算法,创建一棵高度最小的二叉搜索树。
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
我的解答:
树的操作平时遇到很少,要加大训练
给我们的是一个升序的整数数组,在二叉树的遍历中,中序遍历得到的也是一个升序数组,证明这道题是想让我们进行逆操作,把整数数组还原回去,但是又需要是高度最小,高度最小即只在树的最底层存在叶子结点。而为了达到高度最小,我们每次从数组的中间进行递归,二叉搜索树,按照值来判断的话,有:左子树<根<右子树,我们每次从数组的中间进行划分,刚好符合这个条件,另外递归结束的条件是数组里面没有能够划分的值的时候,返回NULL,边界处的判断需要注意,代码如下:
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def sortedArrayToBST(self, nums: List[int]) -> TreeNode: left,right=0,len(nums)-1 if left>right: return None mid=len(nums)//2 root=TreeNode(nums[mid]) root.left=self.sortedArrayToBST(nums[:mid]) root.right=self.sortedArrayToBST(nums[mid+1:]) return root
题目8 ID559
实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
我的解答:
想要知道一棵树是否是平衡的,它的两棵子树高度差需要不超过1,使用GetLength函数求树的深度,check函数判断两个树结点的高度之差是否超过1,超过1返回false,不超过返回true。从根节点开始向下递归,如果当前结点是空节点,则返回true,空树一定是平衡的,否则使用check函数判断其左右子树高度差,若暂时为平衡的,则递归判断左子树和右子树是否是平衡的,若不平衡,则直接返回false,代码如下:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ //求树的深度 int GetLength(struct TreeNode* root){ if(root==NULL){ return 0; } int leftlength=GetLength(root->right); int rightlength=GetLength(root->left); return (leftlength>rightlength?leftlength:rightlength)+1; } bool check(struct TreeNode* left,struct TreeNode* right){ if(GetLength(left)-GetLength(right)>1||GetLength(left)-GetLength(right)<-1){ return false; }else{ return true; } } bool isBalanced(struct TreeNode* root){ if(root==NULL){ return true; } if(check(root->left,root->right)){ return isBalanced(root->left)&&isBalanced(root->right); }else{ return false; } }
题目9 ID530
给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。
示例:
输入:
1
\
3
/
2
输出:
1
解释:
最小绝对差为 1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。
提示:
树中至少有 2 个节点。
本题与 783 https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/ 相同
我的解答:
二叉搜索树的特点是,在任意一个当前结点,如果其左右子树不为空,则左子树的根节点值一定小于当前结点,右子树的根节点值一定大于当前结点,所以我们中序遍历二叉搜索树得到的列表值一定是一个递增数列,得到中序遍历的列表后,计算列表中相邻值的差是否与当前的最小值小,若比当前最小值小,则替换最小值,否则保持不变,继续遍历列表。
代码如下:
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def SortIn(self,root:TreeNode): if root==None: return None self.SortIn(root.left) self.treelist.append(root.val) self.SortIn(root.right) def getMinimumDifference(self, root: TreeNode) -> int: self.treelist=[] self.SortIn(root) minnum=self.treelist[1]-self.treelist[0] for i in range(len(self.treelist)-1): if self.treelist[i+1]-self.treelist[i]<minnum: minnum=self.treelist[i+1]-self.treelist[i] return minnum
题目10 ID559
给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。
例如:
输入: 原始二叉搜索树:
5
/ \
2 13
输出: 转换为累加树:
18
/ \
20 13
我的解答:
从二叉搜索树的特性出发,二叉搜索树的中序遍历结果是一个升序序列,使用SortIn函数中序遍历得到该序列后,我们使用SortInTwo函数重新遍历二叉搜索树,对于每一个结点,我们都遍历升序序列,将大于结点的值加在当前结点val上,使用AddVal函数实现,二叉树遍历结束后,得到的新树就是累加树了。
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def SortIn(self,root:TreeNode): if root==None: return None self.SortIn(root.left) self.sortlist.append(root.val) self.SortIn(root.right) def AddVal(self,root): temp=0 for i in self.sortlist: if i>root.val: temp+=i root.val+=temp def SortInTwo(self,root:TreeNode): if root==None: return None self.SortInTwo(root.left) self.AddVal(root) self.SortInTwo(root.right) def convertBST(self, root: TreeNode) -> TreeNode: self.sortlist=[] self.SortIn(root) self.SortInTwo(root) return root
题目11 ID543
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
1
/ \
2 3
/ \
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
注意:两结点之间的路径长度是以它们之间边的数目表示。
我的解答:
分析题目可以知道求直径实际上是求树结点最大的左子树深度和右子树深度之和,使用maxlength全局变量存储当前最大直径,遍历二叉树,对每一个结点求其左子树和右子树的深度之和,再与maxlength进行比较,大于maxlength则替换,否则maxlength不变,最后返回maxlength。
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ int maxlength=0; int GetTreeLength(struct TreeNode* root){ if(root==NULL){ return 0; } int left=GetTreeLength(root->left); int right=GetTreeLength(root->right); if(left+right>maxlength){ maxlength=left+right; } return (left>right?left:right)+1; } int diameterOfBinaryTree(struct TreeNode* root){ maxlength=0; GetTreeLength(root); return maxlength; }
题目12 ID563
给定一个二叉树,计算整个树的坡度。
一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。
整个树的坡度就是其所有节点的坡度之和。
示例:
输入:
1
/ \
2 3
输出: 1
解释:
结点的坡度 2 : 0
结点的坡度 3 : 0
结点的坡度 1 : |2-3| = 1
树的坡度 : 0 + 0 + 1 = 1
注意:
任何子树的结点的和不会超过32位整数的范围。
坡度的值不会超过32位整数的范围。
我的解答:
按照树节点坡度的定义:该节点左子树的结点之和和右子树结点之和的差的绝对值,使用递归求子树节点之和。我们遍历整棵树,求每个结点的坡度之和即可,使用AbsVal函数求两个数的之差的绝对值。
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ int AbsVal(int a,int b){ if(a>b){ return a-b; } return b-a; } int AddVal(struct TreeNode* root){ if(root==NULL){ return 0; } return root->val+AddVal(root->left)+AddVal(root->right); } int findTilt(struct TreeNode* root){ if(root==NULL){ return 0; } return AbsVal(AddVal(root->left),AddVal(root->right))+findTilt(root->left)+findTilt(root->right); }
题目13 ID572
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
示例 1:
给定的树 s:
3
/ \
4 5
/ \
1 2
给定的树 t:
4
/ \
1 2
返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。
示例 2:
给定的树 s:
3
/ \
4 5
/ \
1 2
/
0
给定的树 t:
4
/ \
1 2
返回 false。
我的解答:
判断二叉树t是否是s的子树,要么t与s是相同的树,要么t是s左子树的子树,要么t是s右子树的子树,以此标准做判断递归。isEqual函数用来判断两棵树是否相同。
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ bool isEqual(struct TreeNode* s,struct TreeNode* t){ if(s==NULL&&t==NULL){ return true; } return s&&t&&(s->val==t->val)&&isEqual(s->left,t->left)&&isEqual(s->right,t->right); } bool isSubtree(struct TreeNode* s, struct TreeNode* t){ if(s==NULL&&t==NULL){ return true; } if(s==NULL&&t!=NULL){ return false; } return isEqual(s,t)||isSubtree(s->left,t)||isSubtree(s->right,t); }
题目14 ID606
你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
空节点则用一对空括号 "()" 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
示例 1:
输入: 二叉树: [1,2,3,4]
1
/ \
2 3
/
4
输出: "1(2(4))(3)"
解释: 原本将是“1(2(4)())(3())”,
在你省略所有不必要的空括号对之后,
它将是“1(2(4))(3)”。
示例 2:
输入: 二叉树: [1,2,3,null,4]
1
/ \
2 3
\
4
输出: "1(2()(4))(3)"
解释: 和第一个示例相似,
除了我们不能省略第一个对括号来中断输入和输出之间的一对一映射关系。
我的解答:
题目描述不太好,事实上,对于左子树为空的时候,需要留()括号,右子树为空的时候,可以直接忽略。我们按照题目要求进行递归。若根节点为空的时候,直接返回空字符串,如果根节点的左子树和右子树都为空的时候,直接返回根节点的val,特殊情况不满足的时候进入正常递归,左子树为空的时候,返回字符串添加(),不为空的话使用()括号包裹左子树的递归值,继续递归左子树,对于右子树,只有当其非空的时候使用括号包裹其递归值,最后返回context结果字符串。
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def tree2str(self, t: TreeNode) -> str: if not t: return "" if not t.left and not t.right: return str(t.val) context=str(t.val) if t.left: context+="("+self.tree2str(t.left)+")" else: context+="()" if t.right: context+="("+self.tree2str(t.right)+")" return context
题目15 ID617
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/ \
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。
我的解答:
我们使用t1二叉树的根节点作为新树的根节点。树合并的时候的操作有:当两棵二叉树的树结点都为空的时候,返回None空节点,当两棵树结点中有一个为空的时候,返回另一颗非空树结点。当两棵树的结点都不为空的时候,将结点值val相加,并存储在t1的值中,同时继续递归两棵二叉树的左子树和右子树,将递归后的树结点赋给t1的左子树或右子树。
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode: if not t1 and not t2: return None if not t1: return t2 if not t2: return t1 if t1 and t2: t1.val+=t2.val t1.left=self.mergeTrees(t1.left,t2.left) t1.right=self.mergeTrees(t1.right,t2.right) return t1
题目16 ID110
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
我的解答:
之前做过相同的题目,再次遇到重做一遍,代码如下:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * }; */ int GetLength(struct TreeNode* root){ if(root==NULL){ return 0; } int leftlength=GetLength(root->left); int rightlength=GetLength(root->right); return (leftlength>rightlength?leftlength:rightlength)+1; } int absval(int a,int b){ if(a>b){ return a-b; } return b-a; } bool CheckTree(struct TreeNode* left,struct TreeNode* right){ if(absval(GetLength(left),GetLength(right))>1){ // printf("%d %d\n",GetLength(left),GetLength(right)); // printf("%d %d\n",left->val,right->val); return false; } return true; } bool isBalanced(struct TreeNode* root){ if(root==NULL){ return true; } return CheckTree(root->left,root->right)&&isBalanced(root->left)&&isBalanced(root->right); }