剑指OFFER DAY7

第 7 天

搜索与回溯算法(简单)DFS&BFS


剑指 Offer 26. 树的子结构

这道题我真的没有做出来,原因是我对二叉树的DFS基础过于薄弱,这里贴一个二叉树的遍历

二叉树遍历DFS/BFS

但是我看了大佬的解题思路,直接看java注释版代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    /*
    参考:数据结构与算法的题解比较好懂
    死死记住isSubStructure()的定义:判断B是否为A的子结构
    */
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        // 若A与B其中一个为空,立即返回false
        if(A == null || B == null) {
            return false;
        }
        // B为A的子结构有3种情况,满足任意一种即可:
        // 1.B的子结构起点为A的根节点,此时结果为recur(A,B)
        // 2.B的子结构起点隐藏在A的左子树中,而不是直接为A的根节点,此时结果为isSubStructure(A.left, B)
        // 3.B的子结构起点隐藏在A的右子树中,此时结果为isSubStructure(A.right, B)
        return recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
    }

    /*
    判断B是否为A的子结构,其中B子结构的起点为A的根节点
    */
    private boolean recur(TreeNode A, TreeNode B) {
        // 若B走完了,说明查找完毕,B为A的子结构
        if(B == null) {
            return true;
        }
        // 若B不为空并且A为空或者A与B的值不相等,直接可以判断B不是A的子结构
        if(A == null || A.val != B.val) {
            return false;
        }
        // 当A与B当前节点值相等,若要判断B为A的子结构
        // 还需要判断B的左子树是否为A左子树的子结构 && B的右子树是否为A右子树的子结构
        // 若两者都满足就说明B是A的子结构,并且该子结构以A根节点为起点
        return recur(A.left, B.left) && recur(A.right, B.right);
    }
}

根据该代码我们可以写出Python版代码

class Solution:
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        def recur(A, B):
            if not B: return True
            if not A or A.val != B.val: return False
            return recur(A.left, B.left) and recur(A.right, B.right)

        return bool(A and B) and (recur(A, B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B))

只能说解法过于精妙,递归中嵌套递归,思路清晰无懈可击,什么时候我能够达到这种水平就出师了。


剑指 Offer 27. 二叉树的镜像

 

这道题我的思路是广度优先遍历将树的值按镜像模式存储在list中,再一个一个从list中把值取出来存成树。其中比较麻烦的是原始输入的树可能不是完全二叉树,需要在空的地方补null,并且反转以后输出不能有null节点 ,所以需要把最后为null的节点去除再将剩下的排列成树。

以下是我思路的代码

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if root == None:return None
        queue = collections.deque([root])
        index = 0
        res = [root.val]
        while queue:
            for _ in range(len(queue)):
                node = queue.popleft()
                if node.right:
                    queue.append(node.right)
                    res.append(node.right.val)
                else:
                    res.append(None)
                if node.left:
                    queue.append(node.left)
                    res.append(node.left.val)
                else:
                    res.append(None)
        while True:
            if res[-1]==None:
                del (res[-1])    
            else:
                break
        new_root = TreeNode(res[index])
        new_queue = collections.deque([new_root])
        while index<len(res):
            node = new_queue.popleft()
            if index+1<len(res):
                node.left = TreeNode(res[index+1])
            if index+2<len(res):
                node.right = TreeNode(res[index+2])
            index += 2
            new_queue.append(node.left)
            new_queue.append(node.right)
        return new_root

 然后我有看到一个思路,我这次只调换root节点和他的左右子节点,然后递归该方法,直到左右子节点不存在及叶子节点return该节点

以下是代码

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if not root :return None
        if root.right==None and root.left==None:
            return root
        root.left,root.right = root.right,root.left
        self.mirrorTree(root.left)
        self.mirrorTree(root.right)
        return root

剑指 Offer 28. 对称的二叉树

 

我的做法,有错误但是我不知道在哪里出错了

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root :return True
        tem = deepcopy(root)
        def mirrorTree(root: TreeNode) -> TreeNode:
            if not root :return None
            if root.right==None and root.left==None:
                return root
            root.left,root.right = root.right,root.left
            mirrorTree(root.left)
            mirrorTree(root.right)
            return root
        return mirrorTree(root) == tem

终于找到问题了,root本身就是树的根节点地址,用==比地址肯定是不能代表树的,就像链表一样,给两个链表头节点,无法比较两个链表是否相等。所以需要挨个比较。

# 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
        tem = deepcopy(root)
        def mirrorTree(root: TreeNode) -> TreeNode:
            if not root :return None
            if root.right==None and root.left==None:
                return root
            root.left,root.right = root.right,root.left
            mirrorTree(root.left)
            mirrorTree(root.right)
            return root

        def isEqual(root1, root2):
            if root1 == None and root2 == None:
                return True
    
            if root1 == None and root2 != None:
                return False
    
            if root1 != None and root2 == None:
                return False
    
            if root1.val == root2.val:
                return isEqual(root1.left, root2.left) and isEqual(root1.right,root2.right)
            else:
                return False
        return(isEqual(mirrorTree(root),tem))

大佬做法

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        def recur(L, R):
            if not L and not R: return True
            if not L or not R or L.val != R.val: return False
            return recur(L.left, R.right) and recur(L.right, R.left)

        return recur(root.left, root.right) if root else True

刷题心得:

python的 == 调用的是类函数的__eq__方法,类比java的equals(); 而python的 is 方法类别java的 == 比较的是地址

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Weber77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值