python_ACM模式《剑指offer刷题》二叉树1

题目:

python_ACM模式《剑指offer刷题》二叉树1_第1张图片

面试tips:

1. 询问是否可以使用双端队列 (看后面思路就可知为什么要问这个)

思路:

时复和空复都为O(n)

思路一:利用双端队列。总体思想是利用二叉树层序遍历(二叉树的层序遍历就是用队列dq,且从左往右每一层存入队列中),但这里的双端队列使用在path中,即存储路径path时,遇到奇数列,从dq中读出来的节点进行尾插入path;遇到偶数列,从dq中读出来的节点进行头插入。

例如:层序遍历对上述二叉树(因为是层序遍历,因此都是从左往右读取的)

第一层读取: 1 。 因为是奇数层,则存入path尾插,则[1]

第二层读取:2 3 。因为是偶数层,则存入path头插,则[3 2](注意先读取先插)

第三层读取:4 5 6 7 。因为是奇数层,则存入path尾插,则[4 5 6 7](注意先读取先插)

第二层读取:8 9 10 11 12 13 14 15 。因为是偶数层,则存入path头插,则[15 14 13 12 11 10 9 8]

        其实本质上思路一是伪Z字形遍历,因为其在第一次pop节点时还是层序的,只是加入路径path时对奇偶列的加入一个是尾插一个是头插。是leetcode上提供的思路。

        而思路二当在pop节点时就已经时Z字形遍历了。是剑指offer提供的思路。

思路二:利用两个栈。分别称为当前栈,下一栈。分析:若当前栈存储的是奇数行的节点时,则处理时将其左右孩子按顺序存入下一栈中(这样下一次就可以输出右左孩子);若当前栈存储的是偶数行的节点时,则处理时将其右左孩子按顺序存入下一栈(这样下一次就可以输出左右孩子)。

具体分析:

当前栈:第一行。-> 弹出节点1,将其左右孩子存入下一栈23。当前栈为空了则将下一栈作为当前栈,当前栈作为下一栈。result[1]

当前栈:此时节点为23,是第二行。->弹出节点3,将其右左孩子存入下一栈76,弹出节点2,将其右左孩子存入下一栈54,则下一栈为7654。当前栈为空了则将下一栈作为当前栈,当前栈作为下一栈。result[32]

当前栈:result[4567]

````直至两个栈都为空。

代码实现:

思路一:

from collections import deque

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def arr2tree(arr, index):
    # 满二叉树数组格式构造二叉树
    # 构造arr[index]的二叉树
    # 满二叉树数组格式: 是指首先按层序遍历顺序,且二叉树的非空节点的左右孩子(尽管为空)都会打印出来,空节点的左右孩子则不打印
    if index >= len(arr) or arr[index] == None:
        return None
    root = TreeNode(val = arr[index])
    left = arr2tree(arr, 2 * index + 1)
    right = arr2tree(arr, 2 * index + 2)
    root.left = left
    root.right = right
    return root


def zigzagLevelOrder(root):
    # 使用双端队列。
    if not root:
        return []
    dq = deque([root])  # 这个作用只是层序遍历的迭代法
    result = []
    sign = True  # 表明当前是奇数行
    while dq:
        size = len(dq)
        path = deque()  # 这里使用双端队列
        while size:
            # 之所以说其是伪Z字形遍历 就是其取出来时还是层序遍历的从左往右,只是对结果集根据奇数列or偶数列头插或尾插
            node = dq.popleft()
            if sign:
                path.append(node.val)
            else:
                path.appendleft(node.val)
            # 下面都是层序遍历的套路 左右孩子往dq中存
            if node.left:
                dq.append(node.left)
            if node.right:
                dq.append(node.right)
            size -= 1
        result.append(list(path))
        sign = not sign
    return result

if __name__ == '__main__':
    arr = [3, 9, 20, None, None, 15, 7]
    root = arr2tree(arr, 0)
    print(zigzagLevelOrder(root))
    # [[3], [20, 9], [15, 7]]


思路二:

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def arr2tree(arr, index):
    # 满二叉树数组格式构造二叉树
    # 构造arr[index]的二叉树
    # 满二叉树数组格式: 是指首先按层序遍历顺序,且二叉树的非空节点的左右孩子(尽管为空)都会打印出来,空节点的左右孩子则不打印
    if index >= len(arr) or arr[index] == None:
        return None
    root = TreeNode(val = arr[index])
    left = arr2tree(arr, 2 * index + 1)
    right = arr2tree(arr, 2 * index + 2)
    root.left = left
    root.right = right
    return root

def zigzagLevelOrder(root) :
    # 利用两个栈解决本题
    # 将奇数层1放入第一个栈中,且放左右孩子在第二个栈中(则下一次就可逆序打印)
    # 偶数层0时(第二个栈)放右左孩子
    if not root:
        return []
    # 定义一个二维数组 分别是两个栈
    stack = [[],[]]
    result = []
    path = []
    # 初始化奇数层、偶数层
    current, next_lay = 1, 0    # 先处理第一层 故当前层是奇数层
    stack[current].append(root)
    while stack[current] or stack[next_lay]:
        # 只要奇数层or偶数层还有节点 说明未遍历完毕
        node = stack[current].pop()
        path.append(node.val)
        if current:
            # 如果是奇数层则先放左孩子再放右孩子(因为下一层要逆序)
            if node.left:
                stack[next_lay].append(node.left)
            if node.right:
                stack[next_lay].append(node.right)
        else:
            # 若是偶数层则先放右孩子
            if node.right:
                stack[next_lay].append(node.right)
            if node.left:
                stack[next_lay].append(node.left)
        if not stack[current]:
            # 如果当前层空了则更换当前层
            result.append(path[:])
            path = []
            current = 1 - current  # 当前层从奇数层更换成偶数层,偶数层更换为奇数层
            next_lay = 1 - next_lay    # 下一层从偶数层更换成奇数层,奇数层更换为偶数层
    return result

if __name__ == '__main__':
    arr = [3, 9, 20, None, None, 15, 7]
    root = arr2tree(arr, 0)
    print(zigzagLevelOrder(root))
    # [[3], [20, 9], [15, 7]]

参考资料:

1. 《剑指offer》

2. 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

你可能感兴趣的:(剑指offer练习,python,开发语言)