剑指offer 二叉树 java

27.二叉树的镜像

dfs(二叉树)

根据观察将每个节点的左右子树都交换,即可满足题意。

那么可以先写一个简单的swap函数,然后在函数里左右递归调用。

class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root==null||(root.left==null&&root.right==null)) return root;
        swap(root);
        mirrorTree(root.right);
        mirrorTree(root.left);
        return root;
    }
    private void swap(TreeNode node){
        if(node==null||(node.left==null&&node.right==null)) return;
        TreeNode temp=node.left;
        node.left=node.right;
        node.right=temp;
    }
}

辅助栈(或队列)

时间复杂度O(N),空间复杂度O(N)

class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null) return null;
        Stack<TreeNode> stack = new Stack<>() {{ add(root); }};
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if(node.left != null) stack.add(node.left);
            if(node.right != null) stack.add(node.right);
            TreeNode tmp = node.left;
            node.left = node.right;
            node.right = tmp;
        }
        return root;
    }
}

28.对称二叉树

比较函数

左子树的右=右子树的左

左子树的左=右子树的右

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return root==null?true:recur(root.left,root.right);
    }

    boolean recur(TreeNode L,TreeNode R){
        if(L==null&&R==null) return true;
        if(L==null||R==null||L.val!=R.val) return false;
        return recur(L.left,R.right)&&recur(L.right,R.left);
    }
}

32-1 从上到下打印二叉树

BFS

class Solution {
    public int[] levelOrder(TreeNode root) {
        if(root == null) return new int[0];
        Queue<TreeNode> queue = new LinkedList<>(){{ add(root); }};
        ArrayList<Integer> ans = new ArrayList<>();
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            ans.add(node.val);
            if(node.left != null) queue.add(node.left);
            if(node.right != null) queue.add(node.right);
        }
        int[] res = new int[ans.size()];
        for(int i = 0; i < ans.size(); i++)
            res[i] = ans.get(i);
        return res;
    }
}

32-II 从上到下打印二叉树II

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root==null) return new LinkedList<>();
        Queue<TreeNode> q =new LinkedList<>(){{add(root);}};

        List<List<Integer>> res = new LinkedList<>();

        while(!q.isEmpty()){
            int sz=q.size();

            List<Integer> track = new LinkedList<>();

            for(int i=0;i<sz;i++){
                TreeNode cur=q.poll();
                track.add(cur.val);
                if(cur.left!=null) q.offer(cur.left);
                if(cur.right!=null) q.offer(cur.right);
            }
            
            res.add(track);
        }
        return res;
    }
}

32-III 从上到下打印二叉树

(1)每层顺序变换的本质在哪里,插入顺序

头插、尾插

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root==null) return new LinkedList<>();
        Queue<TreeNode> q = new LinkedList<>(){{add(root);}};
        List<List<Integer>> res = new ArrayList<>();
        while(!q.isEmpty()){
            int sz =q.size();
            LinkedList<Integer> ans = new LinkedList<>();
            for(int i=0;i<sz;i++){
                TreeNode cur = q.poll();
                if(res.size()%2==0) ans.addLast(cur.val);
                else ans.addFirst(cur.val);
                if(cur.left!=null) q.offer(cur.left);
                if(cur.right!=null) q.offer(cur.right);
            }
            res.add(ans);
        }
        return res;
    }
}

(2)Collections.reverse();

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root==null) return new LinkedList<>();
        Queue<TreeNode> q = new LinkedList<>(){{add(root);}};
        List<List<Integer>> res = new ArrayList<>();
        while(!q.isEmpty()){
            int sz =q.size();
            LinkedList<Integer> ans = new LinkedList<>();
            for(int i=0;i<sz;i++){
                TreeNode cur = q.poll();
                ans.add(cur.val);
                if(cur.left!=null) q.offer(cur.left);
                if(cur.right!=null) q.offer(cur.right);
            }
            if(res.size() % 2 == 1) Collections.reverse(ans);
            res.add(ans);
        }
        return res;
    }
}

33 二叉搜索树的后序遍历

后序遍历的定义:遍历顺序为 左 右 根

二叉搜索树的定义:左子树中所有节点的值<根节点的值;右子树中所有节点的值>根节点的值;其左右子树也分别为二叉搜索树。

 

(1)左右分别递归的做法。

找到左右子树的边界。判断根节点是否大于左边,是否小于右边所有节点

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        if(postorder.length==0||postorder.length==1) return true;
        return recur(postorder,0,postorder.length-1);
    }
    boolean recur(int[] postorder,int i,int j){
        if(i>=j) return true;
        int p=i;
        while(postorder[p]<postorder[j]) p++;
        int m=p;
        while(postorder[p]>postorder[j]) p++;
        return p==j&&recur(postorder,i,m-1)&&recur(postorder,m,j-1);
    }
}

(2)辅助单调栈

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        Stack<Integer> stack = new Stack<>();
        int root = Integer.MAX_VALUE;
        for(int i = postorder.length - 1; i >= 0; i--) {
            if(postorder[i] > root) return false;
            while(!stack.isEmpty() && stack.peek() > postorder[i])
            	root = stack.pop();
            stack.add(postorder[i]);
        }
        return true;
    }
}

34 二叉树中和为某一值的路径

class Solution {
    List<List<Integer>> res = new LinkedList<>();
    LinkedList<Integer> track = new LinkedList<>();
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        dfs(root,target);
        return res;
    }
    private void dfs(TreeNode root,int tar){
        if(root==null) return;
        track.add(root.val);
        tar-=root.val;
        if(tar==0&&root.left==null&&root.right==null) res.add(new LinkedList(track));
        dfs(root.left,tar);
        dfs(root.right,tar);
        track.removeLast();
    }
}

36 二叉搜索树与双向链表

二叉搜索树有序,中序遍历。

加一些指针。

头节点指针。

左右子树指针通过增加一个辅助节点pre=cur完成。

pre==null

    //中序遍历
    void dfs(Node root){
        if(root==null) return;
        dfs(root.left);//左
        System.out.println(root.val);//根
        dfs(root.right);//右
    }
class Solution {
    Node pre,head;
    public Node treeToDoublyList(Node root) {
        if(root==null) return null;
        dfs(root);
        head.left=pre;
        pre.right=head;
        return head;
    }
    //中序遍历
    void dfs(Node cur){
        if(cur==null) return;
        dfs(cur.left);//左
       if(pre!=null) pre.right=cur;
       else head=cur;
       cur.left=pre;
       pre=cur;
        dfs(cur.right);//右
    }
}

37 序列化二叉树

队列去做

public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root==null) return "[]";
        StringBuilder res = new StringBuilder("[");
        Queue<TreeNode> q = new LinkedList<>(){{add(root);}};
        while(!q.isEmpty()){
            TreeNode node = q.poll();
            if(node!=null){
                res.append(node.val+",");
                q.add(node.left);
                q.add(node.right);
            }else{
                res.append("null,");
            }
        }
        res.deleteCharAt(res.length()-1);
        res.append("]");
        return res.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data.equals("[]")) return null;
        String[] vals = data.substring(1,data.length()-1).split(",");
        TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
        Queue<TreeNode> queue =new LinkedList<>(){{add(root);}};
        int i=1;
        while(!queue.isEmpty()){
            TreeNode node= queue.poll();
            if(!vals[i].equals("null")){
                node.left = new TreeNode(Integer.parseInt(vals[i]));
                queue.add(node.left);
            }
            i++;
            if(!vals[i].equals("null")){
                node.right = new TreeNode(Integer.parseInt(vals[i]));
                queue.add(node.right);
            }
            i++;
        }
        return root;
    }
}

54 二叉搜索树的第k大节点

正序:左根右

倒序:右根左

class Solution {
    int res=0;
    TreeNode node;
    public int kthLargest(TreeNode root, int k) {
        dfs(root,k);
        return node.val;
    }
    void dfs(TreeNode root,int k){
        if(root==null) return;
        dfs(root.right,k);
        res++;
        if(k==res) node=root;
        dfs(root.left,k);
    }
}

55-1 二叉树的深度

找最长的那一条    二叉树一般都会考虑递归,因为树是递归定义的

递归写法:左右子树+根节点的1

class Solution {
    public int maxDepth(TreeNode root) {
        return root==null?0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;
    }
}

还可以用bfs去做

55-II 平衡二叉树的深度

此树的深度等于左子树的深度与右子树的深度中的最大值+1.

(1)先序遍历

此方法容易想到,但会产生大量重复计算

class Solution {
    boolean res = true;
    public boolean isBalanced(TreeNode root) {
        depth(root);
        return res;
    }
    int depth(TreeNode root){
        if(root==null) return 0;
        int left=depth(root.left),right=depth(root.right);
        if(Math.abs(left-right)>1) res=false;
        return Math.max(left,right)+1;
    }
}

(2)后序遍历+剪枝

class Solution {
    public boolean isBalanced(TreeNode root) {
        return recur(root) != -1;
    }

    private int recur(TreeNode root) {
        if (root == null) return 0;
        int left = recur(root.left);
        if(left == -1) return -1;
        int right = recur(root.right);
        if(right == -1) return -1;
        return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
    }
}

68-I 二叉搜索树的最近公共祖先

本题给定了两个重要条件:① 树为 二叉搜索树 ,② 树的所有节点的值都是 唯一 的。根据以上条件,可方便地判断 p,q与 root的子树关系,即:

若 root.val < p.val,则 p 在 root右子树 中;
若 root.val > p.val,则 p 在 root 左子树 中;
若 root.val = p.val,则 p 和 root指向 同一节点 。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(root != null) {
            if(root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
                root = root.right; // 遍历至右子节点
            else if(root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
                root = root.left; // 遍历至左子节点
            else break;
        }
        return root;
    }
}

递归

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root.val < p.val && root.val < q.val)
            return lowestCommonAncestor(root.right, p, q);
        if(root.val > p.val && root.val > q.val)
            return lowestCommonAncestor(root.left, p, q);
        return root;
    }
}

68-II 二叉树的最近公共祖先

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left == null && right == null) return null; // 1.
        if(left == null) return right; // 3.
        if(right == null) return left; // 4.
        return root; // 2. if(left != null and right != null)
    }
}

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值