刷题之前,要知道leetcode的标签主要包括什么:
一. 算法问题主要包括:
分治, 二分查找, 贪心算法
排序问题包括:快速排序, 归并排序, 计数排序
搜索问题包括: 回溯, 递归, 深度优先, 广度优先, 二叉树搜索
图论问题: 最短路径, 最小生成树
动态规划: 背包问题,最长子序列
二. 数据结构问题主要包括:
数组与链表
栈与队列
哈希表
堆
树与图
字符串
三. 下面开始每日记录题目与思考总结:
二叉树
22.03.04:
98. 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树
解题思路: 采用中序遍历的方法。中序遍历: 左中右。其中,左 小于 中,中 小于 右。将二叉树进行中序遍历,每个值存入stack中,查看stack的值是否为有序
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
res=[]
def help(root):
if not root: return None
help(root.left)
res.append(root.val)
help(root.right)
help(root)
print(res)
for i in range(len(res)-1):
if res[i]>=res[i+1]:
return False
return True
其中,中序遍历算法模板如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
res=[]
def midhelp(root):
if not root.left or not root.right: return None
midhelp(root.left)
res.append(root.val)
midhelp(root.right)
midhelp(root)
110. 给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
思路1: 计算出每个节点的左右最大深度,并对节点进行遍历(自顶而下)
计算节点最大深度代码如下:
def maxdeep(root: TreeNode):
if not root:
return 0
return max(maxdeep(root.left),maxdeep(root.right))+1
题解代码如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def maxdeep(root: TreeNode):
if not root:
return 0
return max(maxdeep(root.left), maxdeep(root.right))+1
if not root: return True
return abs(maxdeep(root.left)-maxdeep(root.right))<=1 and self.isBalanced(root.left) and self.isBalanced(root.right)
存在的问题: 每经过一个root,都要循环一边,非常耗时。时间复杂度为O(n方)
更新的思路:从底而上,但是我写不出来 ToT
22.03.05
114. 给你二叉树的根结点 root ,请你将它展开为一个单链表:
展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。
解题思路1:先将二叉树用前序遍历,将每个节点存放在一个列表中(注意:存放的是节点,不是int值),之后遍历列表,让当前值等于新建的root,下一个值等于新建root.right, root.left为None
class Solution:
def flatten(self, root: TreeNode) -> None:
a=list()
def previous(root:TreeNode):
if root:
a.append(root)
previous(root.left)
previous(root.right)
previous(root)
for i in range(len(a)-1):
p,c=a[i],a[i+1]
p.left=None
p.right=c
其中,前序遍历的方法为:
def previous(root:TreeNode):
if root:
if not root:
return None
a.append(root)
previous(root.left)
previous(root.right)
112. 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
题解思路:
22.03.11
111. 计算二叉树最小深度
解题思路:二叉树最小深度定义为根节点到叶子节点的最小距离。那么如果遇到如:[1,2], [1,Null, 2]这样的二叉树,其最小深度应该为2
流程如下:如果二叉树为空,返回0。如果只有根节点,返回1。 如果一侧无节点,返回有节点一侧的最小深度。代码如下:
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:
return 0
if not root.left and not root.right:
return 1
if not root.left:
return 1 + self.minDepth(root.right)
if not root.right:
return 1 + self.minDepth(root.left)
return 1 + min(self.minDepth(root.left),self.minDepth(root.right))
二分查找
22.03.09
33. 题目描述:整数数组 nums 按升序排列,数组中的值互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1
解题思路: 典型的二分查找需要数组由小到大排列,此题在不确定的位置将数组旋转,我们需要在得到的新数组中找target。将数组一分为二后,一定有一般是有序数组,一半是旋转数组。那么我们将有序的一部分用二分查找,旋转数组部分再进行分割。
class Solution:
def search(self, nums: List[int], target: int) -> int:
if not nums: return -1
l, r= 0, len(nums)-1
while l<= r:
m= (l+r)//2
if target==nums[m]:
return m
if nums[0]<=nums[m]:
if nums[l]<=target<nums[m]:
r=m-1
else: l=m+1
else:
if nums[m]<target<=nums[r]:
l=m+1
else: r=m-1
return -1