***leetcode刷题_day12_(树)_code100(相同树)_code94(二叉树中序遍历)

code100:same tree

Given two binary trees, write a function to check if they are the same or not.

Two binary trees are considered the same if they are structurally identical and the nodes have the same value.

Example 1:

Input: 1 1
/ \ /
2 3 2 3

    [1,2,3],   [1,2,3]

Output: true
Example 2:

Input: 1 1
/
2 2

    [1,2],     [1,null,2]

Output: false
Example 3:

Input: 1 1
/ \ /
2 1 1 2

    [1,2,1],   [1,1,2]

Output: false

解答:
根据之前涉及到深度优先广度优先算法可以想到有queue来求解,即先进先出。(heap则可以做到先进后出)

  1. 一般情况:先将root放入队列中,然后循环,当队列不为空的时候,get队列元素。两个队列元素进行判断:
    1 如果都为None,则continue(表示同时到了边界节点)
    2 如果有一个为None,则直接return False(一个到了边界节点,一个没到)这时 经过上面的筛选,这里直接用or即可表示条件。
    3 如果.val不相等,直接return False(该点对应值不等)
    4 如果遍历完成,则return Ture
  2. 临界点:初始为空的情况。其实也可以直接放在一般情况中,因为会进入continue 然后遍历到空,return True。 初始一个为空,直接return False。

代码:

import queue
class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        



        myqueue1 = queue.Queue()
        myqueue2 = queue.Queue()
        myqueue1.put(p)
        myqueue2.put(q)

        while not myqueue1.empty() and not myqueue2.empty():
            a = myqueue1.get()
            b = myqueue2.get()

            #if a == b and (myqueue1):
            if a == None and b ==None:
                continue

            if a == None or b == None:
                return False


            if a.val != b.val:
                return False

            else:
                myqueue1.put(a.left)
                myqueue1.put(a.right)
                myqueue2.put(b.left)
                myqueue2.put(b.right)
        return True

PS:
对于这种需要一个个对比的情况,可以使用递归进行
理解为:一旦一环出现False,则返回为Falseand的连接

步骤:
每次进入递归,会出现以下情况:
1 两个全为None 则返回True(如果分支为这种情况,意味着该分支终结,返回True的话,会继续加and进行判断,意味着该分支的终结以及该分支没有问题)
2 其中一个为None,返回False(只要出现这种情况,最后的全局为False)
3 如果两个的.val相等,进入递归(这种情况意味着根节点本身有值且相等,进入其子节点进行考察)
4 如果两个的.val不相等,返回False

1 2 4 是递归的终止条件 3是递归的启动条件

代码:

class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:

        if p == None and q == None:
            return True
        if p == None or q==None:
            return False
        elif p.val != q.val:
            return False
        else:
            return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right)

需要思考:
递归与正向迭代的关系!!!

code94: Binary Tree Inorder Traversal

Given a binary tree, return the inorder traversal of its nodes’ values.

Example:

Input: [1,null,2,3]
1

2
/
3

Output: [1,3,2]

解答:
一般树的遍历都是可以用到队列或者堆这样的数据结构的

这里中序遍历,顺序为 左 中 右,考虑采用迭代的方法,使用堆(stack)进行 先进后出的操作。
1 因为迭代传入需要有堆进行传递,所以新建run方法,参数为 root(当前节点) stack。
2 对于python来说,堆 可以用 queue.LifoQueue()来表示。这是一个先进后出队列。
3 考虑迭代:
1) 迭代发生的条件1: 因为遍历顺序应该是先右再中再左。所以当存在右节点时,进入迭代。
2) 迭代发生的条件2:1中的迭代进行到最后应该是 遍历到 root节点。这时需要进入左子节点(如果存在)。同样进入左节点后先检查右节点的情况,存在则进入右节点,迭代。
3) 需要注意的是,不管迭代到哪一步 ,在结果回来的时候,都要在 右 的后面 接上 root.val
简单地说,先进入右节点迭代,迭代完(或者没有迭代),导入root.val,然后进行左节点的迭代。这样的操作 会覆盖边界情况,如果没有子节点进行迭代时,仅仅返回 当前节点的val。

4 最后进行堆数据的获取。

代码:

import queue
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        a = queue.LifoQueue()
        #heapq.heapify(a)

        if root == None:
            return []
        else:
            arr = []
            '''
            if root.right:
                self.run(root.right, a)

            
            a.put(root.val)
            #heapq.heappush(a, root.val)
           
            if root.left:
                self.run(root.left, a)
            '''
            self.run(root,a)
            
            
            while not a.empty():
               arr.append(a.get())
            return arr
        

    def run(self, root, a):

        if root.right:
            self.run(root.right, a)
            
      
        a.put(root.val)
        

            
        if root.left:
            self.run(root.left, a)

这里我们使用了后进先出队列的同时也使用了迭代。还有其他方法:
比如官网提供的直接使用stack的情况。直接用的循环。
(这个用法才是大多数树的遍历使用方式)
过程:
1 往stack中注入左节点(条件是左节点存在),每次进入下一层同时要将root.val存入stack中。
2 不存在左节点时,取出stack值,注入数组res中。同时将该值对应的节点的右节点注入stack中(如果右节点存在的话),同样要进行判断之前的两个判断。
3 有点类似于迭代的循环。
简单说就是:现将根节点置入 stack中,检测 如果存在左节点,则将其置入stack中,然后没有左节点了,(如果stack不为空) 就 pop stack值(如果空就退出),如果其存在右节点,就直接 push进stack。 然后再pop 依次循环做到最后。

但是实际操作中,根据是否有左右节点 来判断会有不对的地方。因为tree点不删除子节点的话,遍历过来都会出现再度循环的情况(再度进入左节点)

修改:
我们使用一个操作参数 operate。这个参数作为判断的条件。
1 我们的目的是,先将左放在stack,然后取出的时候将右放在stack。右内再进行左的操作。root节点取出后还要放置右节点。
2 一般情况:
1) 进入循环second,如果operate不为None(初始赋值为root)?放左节点?不行,因为左节点会空,所以放自己。 operate=operate.left。
2) 这层循环出来以后,遍历来到最左节点的left 为空。
3)取出该点,val放入res中。然后operate=operate.right(之所以这样,是为了进入的循环second中。如果右节点 存在左节点,当然是优先处理)。外层加一个循环first,如果stack不为空,就继续。
4)这样处理的话,就需要stack进入时就不为空。为了均衡,将循环first的条件修改为 stack不为空或者operate!=None。也就是stack以及operate均为空就停止运行。
代码:

import queue


class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        a = queue.LifoQueue()
        # heapq.heapify(a)

        if root == None:
            return []
        else:
            res = []
            #a.put(root)
            operate = root
            while not a.empty() or operate != None:
                while operate:
                    a.put(operate)
                    operate = operate.left
                operate = a.get()
                res.append(operate.val)
                print(res)
                operate = operate.right
            return res

理解:
边界root为None依然可以带入。(不需要额外的判断)

对于循环:
操作点 进行 入栈(如果有值),没有值 就出栈一个元素(左) 给到 res;
操作点为出栈点向右移。右移没有值的话继续 出栈 赋值 右移。 有值的话, 入栈。
这样就实现了 左边全入栈 ,出栈的时候 右边有的话 再检查其左边 再全入栈 没有就直接 出栈。 所有的右节点 都被当做 root节点处理完成的(即没有右节点的root节点)

这个方法需要记住!!!很重要。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值