我的解法:
# 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 or q):
return not bool(p)^bool(q)
queue = [(p, q)]
while queue:
t1, t2 = queue.pop(0)
if bool(t1) ^ bool(t2):
return False
if not (bool(t1) | bool(t2)):
continue
if t1.val != t2.val:
return False
queue.append((t1.left, t2.left))
queue.append((t1.right, t2.right))
return True
首先判别特殊情况,若两棵树一个为空一个不为空,返回False;若两棵都为空,返回True。利用元组队列遍历两颗树,比较两棵树对应节点,若对应节点不想等或一个为空一个不为空,终止循环返回False,否则继续执行,直至队列为空。
大佬解法:
# 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)
递归算法。首先列举各种终止条件,两个节点都为空返回True,任意一个为空返回False,两个节点值不相等返回False,再递归至左右节点的相等判断。
我的解法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
queue = [(root.left, root.right)]
while queue:
t1, t2 = queue.pop(0)
if (not t1) and (not t2):
continue
if (not t1) or (not t2):
return False
if t1.val != t2.val:
return False
queue.append((t1.left, t2.right))
queue.append((t1.right, t2.left))
return True
与判断相同树类似,判断根节点是否为空后,取左右子树做类似基于队列的迭代操作。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
def ivs_eql(lt, rt):
if (not lt) and (not rt):
return True
if (not lt) or (not rt):
return False
if lt.val != rt.val:
return False
return ivs_eql(lt.left, rt.right) and ivs_eql(lt.right, rt.left)
return ivs_eql(root.left, root.right)
递归算法,判断两子树是否对称相等。
我的解法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
queue = [(1, root)]
while queue:
depth, node = queue.pop(0)
if node.left:
queue.append((depth+1, node.left))
if node.right:
queue.append((depth+1, node.right))
return depth
建立队列遍历树,依次压入各个节点及其对应的深度,返回遍历结束后的深度。
大佬解法:
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
return max([self.maxDepth(root.left), self.maxDepth(root.right)]) + 1
递归算法,父节点最大深度等于两子节点最大深度加一。
我的解法:
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = [(d, root)]
vals = [[]]
while queue:
d, node = queue.pop(0)
vals[d-1].append(node.val)
if node.left:
queue.append((d+1, node.left))
if node.right:
queue.append((d+1, node.right))
if (node.left or node.right) and len(vals)<=d+1:
vals.append([])
return vals[::-1]
实际为自顶向下遍历再倒转。利用记录树深度的队列自顶向下遍历树,遍历同时将不同深度的节点值记录到嵌套列表中。每层遍历中若深度增加,则在嵌套列表中再添加一个新列表以储存下一深度节点值。
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
if len(nums) == 0:
return None
n = len(nums)
node = TreeNode(nums[n//2])
node.left = self.sortedArrayToBST(nums[:n//2])
node.right = self.sortedArrayToBST(nums[n//2+1:])
return node
递归算法,利用平衡二叉搜索树的子树也是平衡二叉搜索树,每层递归定义一个父节点。
我的解法:
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def depth(node):
if not node:
return 0
return max([depth(node.left), depth(node.right)])+1
if not root:
return True
return (abs(depth(root.left)-depth(root.right)) < 2) and (self.isBalanced(root.left)) and (self.isBalanced(root.right))
定义函数depth计算树的深度,基本思路为树深度为两子树深度最大值加1。若树为平衡二叉树,则每个树节点的左右子树深度之差小于等于1。因此需要递归判断各节点对应子树的左右子树高度差是否小于等于1,且左右子树都为平衡二叉树。深度计算时间复杂度为logn, 遍历节点时间复杂度n,总时间复杂度O(nlogn)。
大佬解法:
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def helper(node):
if not node:
return 0
left = helper(node.left)
if left == -1:
return -1
right = helper(node.right)
if right == -1:
return -1
return max([left+1, right+1]) if abs(left-right)<2 else -1
if not root:
return True
return helper(root) != -1
在计算子树高度时,同时判断该子树是不是平衡二叉树,若不是高度记为-1。若某树的子树高度为-1,整棵树的高度也为-1,那么整棵树不是平衡二叉树。
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:
return 0
if root.left and not root.right:
return self.minDepth(root.left)+1
if not root.left and root.right:
return self.minDepth(root.right)+1
return min([self.minDepth(root.left)+1, self.minDepth(root.right)+1])
递归算法。对任意节点,若它的左右子节点都存在,它的最小深度为左右子节点最小深度较小值加1;若左右子节点只有一个存在,它的最小深度为存在节点最小深度加1;若无子节点,其最小深度为1。
我的解法:
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
queue = [(root.val, root)]
while queue:
s, node = queue.pop(0)
if (s == sum) & ((not node.left) & (not node.right)):
return True
if node.left:
queue.append((s+node.left.val, node.left))
if node.right:
queue.append((s+node.right.val, node.right))
return False
遍历整棵树,每个节点记录自根节点始到当前节点的加和值,若该节点加和值等于目标值且该节点为叶节点,返回True,否则继续遍历,直至最终无满足条件节点,返回False。
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
sum -= root.val
if (sum == 0) and (not root.left) and (not root.right):
return True
return self.hasPathSum(root.left, sum) or self.hasPathSum(root.right, sum)
递归算法,判断当前节点是否是叶节点且满足sum条件,若不满足则用sum减去当前节点值分别作为左右子节点的目标值递归调用本函数。
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
tri_list = [[1]]
for i in range(1,numRows):
new_row = tri_list[i-1]+[0]
for j in range(1,len(new_row)):
new_row[j] += tri_list[i-1][j-1]
tri_list.append(new_row)
return tri_list[:numRows]
利用杨辉三角的每行为上一行的错一位相加,逐层产生杨辉三角每一层输出。
我的解法:
class Solution:
def getRow(self, rowIndex: int) -> List[int]:
l = [1]
for k in range(0, rowIndex):
l += [1]
for i in range(k,0,-1):
l[i] = l[i]+l[i-1]
return l
动态规划,每层除第一和最后一个元素外,第i个元素的更新可以满足l[i] = l[i] + l[i-1],为了防止前一位元素的更新对后续元素更新的影响,每层元素更新时,采用从后往前更新。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
min_num = prices[0]
profit, max_prf = 0, 0
for i in range(1, len(prices)):
if prices[i] < min_num:
min_num = prices[i]
else:
profit = prices[i] - min_num
max_prf = max([profit, max_prf])
return max_prf
遍历一遍数组找到最大利润,关键在于记录更新遍历过程中的当前最小值以及当前最大利润。若遍历到的元素小于当前最小值,则更新当前最小值,其余情况下计算当前遍历到的元素与当前最小值的差,更新差的最大值记录。时间复杂度O(n)。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
d = {
}
for num in nums:
if not d.get(num):
d[num] = 1
else:
d[num] += 1
for n in d:
if d[n] == 1:
return n
遍历数组,用字典记录每个值出现的次数,再遍历一次字典,返回值为1的元素,时间复杂度O(n),空间复杂度O(n)。
大佬解法:
class Solution:
def singleNumber(self, nums: List[int]) -> int:
return reduce(lambda x,y: x^y, nums)
运用亦或位运算,利用性质a⊕a = 0, a⊕0 = a,最终唯一元素结果即为a1⊕a2⊕…⊕an。时间复杂度O(n),空间复杂度O(1)。
我的解法:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
if not head:
return
d = {
head:1}
while 1:
if head.next is None:
return False
elif d.get(head.next):
return True
else:
d[head.next] = 1
head= head.next
遍历链表,利用字典记录出现过的节点,若遍历到的节点存在于字典中,则该链表存在环;若遍历到None,则该链表不存在环。时间复杂度O(n),空间复杂度O(n)。
大佬解法:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
if not head:
return
p, q = head, head
while 1:
if (q is None) or (q.next is None):
return False
q = q.next.next
p = p.next
if p == q:
return True
使用双指针,其中一个指针一次向前移动一格,另一个一次向前移动两格。若快指针遇到None,则该链表中没有环;若快指针与慢指针重合,则说明链表中有环,快指针追上了慢指针。时间复杂度O(n),空间复杂度O(1)。
我的解法:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
na, nb, A, B = 0, 0, headA, headB
while A:
na += 1
A = A.next
while B:
nb += 1
B = B.next
if na >= nb:
for i in range(0,na-nb):
headA = headA.next
else:
for i in range(0,nb-na):
headB = headB.next
while 1:
if not (headA or headB):
return None
if headA == headB:
return headA
headA = headA.next
headB = headB.next
首先分别遍历两链表,分别得到两个链表的长度,长度较长的链表头指针向后移动,保证两个链表长度相同后开始同时遍历,一一比对各自的节点,若出现相同节点,则返回当前节点;若到链表尾仍然没有出现相同节点,返回None。时间复杂度O(n+m),空间复杂度啊O(1)。
大佬解法:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
pA, pB = headA, headB
while 1:
if pA == pB:
return pA
if (not pA) and (not pB):
return
if not pA:
pA = headB
pB = pB.next
elif not pB:
pB = headA
pA = pA.next
else:
pA = pA.next
pB = pB.next
神奇解法,当pA遍历到链表尾后,指向B链表头部,当pB遍历到链表尾后,指向A链表头部。当较长链表指针指向较短链表头部后,两链表待比较长度相同,此时再遍历一遍短链表即可判断是否为相交链表。时间复杂度O(n+m),空间复杂度啊O(1)。(其实和我的解法是一样的,还是我的解法更好懂啊!)