leetcode算法题-剑指Offer篇(11)

1、二叉搜索树的后序遍历序列

1.1 题目描述:

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

1.2 题解
1.2.1 递归

后序遍历定义: [ 左子树 | 右子树 | 根节点 ] ,即遍历顺序为 “左、右、根” 。
二叉搜索树定义: 左子树中所有节点的值 << 根节点的值;右子树中所有节点的值 >> 根节点的值;其左、右子树也分别为二叉搜索树。

    public boolean verifyPostorder(int[] postorder) {
        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++;//找到右子树
        //p==j 只有左子树,正确
        // 继续进行做左右子树的判断
        return p == j && recur(postorder, i, m - 1) && recur(postorder, m, j - 1);
    }
1.2.2 辅助单调栈
 public boolean verifyPostorder(int[] postorder) {

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

            stack.add(postorder[i]);
        }
        return true;
    }
   

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

2.1 题目描述:

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

2.2 题解
2.2.1 递归

后序遍历定义: [ 左子树 | 右子树 | 根节点 ] ,即遍历顺序为 “左、右、根” 。
二叉搜索树定义: 左子树中所有节点的值 << 根节点的值;右子树中所有节点的值 >> 根节点的值;其左、右子树也分别为二叉搜索树。

    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        help(res, list,root, sum);
        return res;
    }

    public void help(List<List<Integer>> res,  List<Integer> list,TreeNode node, int sum) {
        if (node==null)
            return;
        sum=sum-node.val;
        list.add(node.val);
        if(sum==0&&node.left==null&&node.right==null)
            res.add(new ArrayList<>(list));
        help(res,list,node.left,sum);
        help(res,list,node.right,sum);
        list.remove(list.size()-1);
    }

3、复杂链表的复制

3.1 题目描述:

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

在这里插入图片描述

3.2 题解
3.2.1
     public Node copyRandomList(Node head) {
        if (head == null) return head;

        //在每个Node后面新建一个Node做自己的copy
        copy(head);
        // 先处理random域,因为需要用到next域
        handleRandom(head);

        // 需要暂存copyHead,因为后续会改变next域
        Node res = head.next;

        handleNext(head);

        return res;
    }


    private void copy(Node head){

        while (head != null) {
            Node tmp = head.next;
            Node copy = new Node(head.val);

            head.next = copy;
            copy.next = tmp;

            head = tmp;
        }
    }

    private void handleRandom(Node head){
        while (head != null) {
            // 把copy节点的random也指向copy节点
            Node copy = head.next;
            // 注意:random可能指向null,此时不能指向其next结点
            if (head.random != null) {
                copy.random = head.random.next;
            }

            head = copy.next;
        }
    }

    // 处理next域 , 这里需要把源和copy节点一起处理,因为next结点是相关的。
    // 若单处理一者,循环后,另一个就没办法找到属自己类的结点了。
    // 两者处理相同: curNode.next = curNode.next.next
    // 源 -> copy -> {源 -> copy}+ -> null
    private void handleNext(Node cur){
        // 循环条件无需为: cur!=null
        while (true) {
            // 处理最后一个 源结点,指回null
            // 而在这之前,cur都不可能为空
            if (cur.next != null && cur.next.next == null) {
                cur.next = null;
                break;
            }

            Node tmp = cur.next;
            cur.next = tmp.next;
            cur = tmp;
        }
    }


3.2.2 利用HashMap
      public Node copyRandomList(Node head) {
        HashMap<Node,Node> map = new HashMap<>(); //创建HashMap集合
        Node cur=head;
        //复制结点值
        while(cur!=null){
            //存储put:<key,value1>
            map.put(cur,new Node(cur.val)); //顺序遍历,存储老结点和新结点(先存储新创建的结点值)
            cur=cur.next;
        }
        //复制结点指向
        cur = head;
        while(cur!=null){
            //得到get:<key>.value2,3
            map.get(cur).next = map.get(cur.next); //新结点next指向同旧结点的next指向
            map.get(cur).random = map.get(cur.random); //新结点random指向同旧结点的random指向
            cur = cur.next;
        }

        //返回复制的链表
        return map.get(head);


    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值