leetcode652. 寻找重复的子树

leetcode652. 寻找重复的子树


给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。

两棵树重复是指它们具有相同的结构以及相同的结点值。

示例 1:

   1
  / \
 2   3
/   / \
4   2   4
/
4

下面是两个重复的子树:

 2
/
4


4
因此,你需要以列表的形式返回上述重复子树的根结点。

思路1暴力解决

我没有想到下面的序列化解法.用hashmap存储已经访问过的节点,值作为key,value是一个list,包含所有值为key的节点,然后每次遍历到相同值得节点时候去访问list,看list里面的节点有没有和当前节点的结构一样的,没有一样的就加入ans中.

class Solution {
    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        traverse(root);
        return ans;
    }
    public HashMap<Integer,ArrayList>map=new HashMap<>();
    public ArrayList<TreeNode>ans=new ArrayList();
    public void traverse(TreeNode root){
        if(root==null)return;
        if(!map.containsKey(root.val)){
            ArrayList<TreeNode>list=new ArrayList<>();
            list.add(root);
            map.put(root.val,list);
        }else{
            ArrayList<TreeNode>list=map.get(root.val);
            for(TreeNode node:list){
                boolean j=judge(node,root);
                if(j){
                    boolean j2=false;
                    //防止加入结构一样的节点
                    for(TreeNode tn:ans){
                        j2=judge(tn,root);
                        if(j2==true)break;
                    }
                    if(!j2)ans.add(root);
                }
            }
            list.add(root);
        }
        traverse(root.left);
        traverse(root.right);
    }
    public boolean judge(TreeNode nodeA,TreeNode nodeB){
        if(nodeA==nodeB&&nodeA==null)return true;
        if((nodeA==null&&nodeB!=null)||(nodeA!=null&&nodeB==null))return false;
        if(nodeA.val==nodeB.val){
            boolean left=judge(nodeA.left,nodeB.left);
            boolean right=judge(nodeA.right,nodeB.right);
            return left&&right;
        }
        return false;
    }
}

解法二:序列化

把每个子树序列化变成字符串,这样就只需比较字符串是否一样就可以了.
下面还对他做了优化,map存储,key是字符串,value是他出现的次数,如果次数为2,那么就说明出现了两次,这样还能解决多次相同结构子树的判断.
并且后序遍历是自底向上的,只需要遍历n个节点. 而前序遍历和中序遍历都是自顶向下,如果这么构造序列会需要n2的复杂度.(这是新学到的)

class Solution {
     public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        Map<String, Integer> map = new HashMap<String, Integer>();
        List<TreeNode> res = new ArrayList<TreeNode>();
        findDuplicateSubtrees(root, res, map);
        return res;
    }
    
    private StringBuilder findDuplicateSubtrees(TreeNode root, List<TreeNode> res, Map<String, Integer> map){
        if(root == null){
            return new StringBuilder("$");
        }
        StringBuilder left = findDuplicateSubtrees(root.left, res, map);
        StringBuilder right = findDuplicateSubtrees(root.right, res, map);
        //注意这里的加和顺序
        // StringBuilder treeKey = left.append(new StringBuilder(root.val + "")).append(right);
        StringBuilder treeKey = new StringBuilder(root.val + "").append(left).append(right);
        map.put(treeKey.toString(), map.getOrDefault(treeKey.toString(), 0) + 1);
        if(map.get(treeKey.toString()) == 2){
            res.add(root);
        }
        return treeKey;
    }
}

leetcode 61/100

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值