[剑指Offer]32~35
[剑指Offer]32~35
学习使用工具
剑指Offer http://itmyhome.com/sword-means-offer/sword-means-offer.pdf
LeetCode的剑指Offer题库 https://leetcode.cn/problemset/all/
剑指 Offer 32 - III. 从上到下打印二叉树 III
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
例如:
给定二叉树: [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[20,9],
[15,7]
]
提示:
节点总数 <= 1000
解法:
在32-II题的基础上再增加一个层计数level。当level为奇数时,正常将lres加入res;当level为偶数时,将lres的倒序加入res。
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = collections.deque()
res = []
lres = []
num = 1
temp = num
flag = 0
level = 1
queue.append(root)
while queue:
node = queue.popleft()
lres.append(node.val)
if node.left:
queue.append(node.left)
else: flag += 1
if node.right:
queue.append(node.right)
else: flag += 1
temp -= 1
if temp <= 0 :
if level % 2 == 0:
res.append(lres[::-1])
else:
res.append(lres)
lres = []
num *= 2
num -= flag
temp = num
flag = 0
level += 1
return res
正常的做法:这道题的思想就是奇数行正常遍历,偶数行进行从右到左遍历。设置一个标志位level判断当前行是奇数行还是偶数行,如果是奇数行,那下一行就是偶数行,我们可以将当前节点的子节点从左到右入栈,然后出栈的时候赋给队列就是从右到左;同理当前行如果是偶数行,说明下一行就是奇数行,那我们将子节点入栈的时候从右到左,出栈时候的顺序就是从左到右。
剑指 Offer 33. 二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true
,否则返回 false
。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
5
/ \
2 6
/ \
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
提示:
数组长度 <= 1000
解法:
如果某个数组为一个二叉树的后序遍历,那么它满足以下条件:
- 数组最后一个元素为二叉树的根节点;数组前半部分的元素都比根节点小,为左子树;数组后半部分(除了根节点本身)的元素都比根节点大,为右子树
- 左子树和右子树也满足上一条性质
根据以上性质,二分+递归判断即可。
def verifyPostorder(self, postorder: List[int]) -> bool:
if not postorder:
return True
def check(postorder: List[int]):
length = len(postorder)
if length <= 2:
return True
key = postorder[-1]
i = -1
while(postorder[i + 1] < key):
i += 1
if postorder[i + 1: length - 1] and min(postorder[i + 1: length - 1]) < key:
return False
return check(postorder[0 : i]) and check(postorder[i + 1: length - 1])
return check(postorder)
剑指 Offer 34. 二叉树中和为某一值的路径
给你二叉树的根节点 root
和一个整数目标和 targetSum
,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例 2:
输入:root = [1,2,3], targetSum = 5
输出:[]
示例 3:
输入:root = [1,2], targetSum = 0
输出:[]
提示:
- 树中节点总数在范围
[0, 5000]
内 -1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
解法:
递归遍历+回溯。使用一个temp数组记录满足条件的路径,若满足则加入结果数组。
def pathSum(self, root: TreeNode, target: int) -> List[List[int]]:
if not root:
return []
res = []
temp = []
sum = 0
def travel(root: TreeNode, temp: List[int], sum):
sum += root.val
temp.append(root.val)
if sum == target and not root.left and not root.right:
res.append(temp[:])
if root.left:
travel(root.left, temp, sum)
if root.right:
travel(root.right, temp, sum)
temp.pop()
travel(root, temp, sum)
return res
剑指 Offer 35. 复杂链表的复制
请实现 copyRandomList
函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next
指针指向下一个节点,还有一个 random
指针指向链表中的任意节点或者 null
。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
提示:
-10000 <= Node.val <= 10000
Node.random
为空(null)或指向链表中的节点。- 节点数目不超过 1000 。
解法:
因为Random节点的存在而无法通过仅一遍遍历就复制建立新链表。因此,借助字典,第一次遍历的时候建立无索引的新节点,第二次遍历的时候再建立next和random索引。
def copyRandomList(self, head: 'Node') -> 'Node':
if not head: return
dic = {}
cur = head
while cur:
dic[cur] = Node(cur.val)
cur = cur.next
cur = head
while cur:
dic[cur].next = dic.get(cur.next)
dic[cur].random = dic.get(cur.random)
cur = cur.next
return dic[head]