堆和树的相关问题

堆和树的相关问题

1.堆

1.1 求数组中第K大的元素

使用堆结构寻找数组中第K大的元素的实现思路如下:

        构建最小堆:首先,我们可以将待处理的数组元素构造成一个最小堆。在最小堆中,父节点的值总是小于或等于其子节点的值,这意味着堆顶元素始终是最小的。

        删除前K-1个元素:由于我们要找的是第K大的元素,因此我们从堆顶开始,连续删除(交换堆顶元素与最后一个元素并缩小堆大小)K-1次最小元素。这样,在删除了K-1个最小元素后,堆顶的元素就是原数组中的第K大元素。

具体步骤如下:

        初始化一个大小为k的小顶堆,并从数组中选取前k个元素放入堆中。
        对这个小顶堆进行调整,确保满足堆性质。
        然后,循环k-1次:
        弹出堆顶元素(即当前最小元素),并将堆大小减一。
        将堆外的下一个元素(即当前堆大小位置的数组元素)入堆,并重新调整堆。
        当循环结束后,堆顶元素即为数组中第K大的元素。
        这种方法的时间复杂度主要取决于堆的构造和K-1次删除操作,总体时间复杂度为O(n + klogk),其中n是数组长度,当k相对于n较小的时候,这种方法效率较高


/*
 * 小顶堆
 * */
public class MinHeapFindK {
    public static void main(String[] args) {
        MinHeapFindK minHeapFindK = new MinHeapFindK();
       /*  int k = minHeapFindK.findK(new int[]{3, 2, 1, 5, 6, 4}, 2);
        System.out.println(k);
        int k1 = minHeapFindK.findK(new int[]{3, 2, 3,1, 2,4,5,5, 6}, 4);
        System.out.println(k1);
       */
//        int k1 = minHeapFindK.findK(new int[]{3, 2, 1, 5, 6, 4}, 2);
        int k2 = minHeapFindK.findK(new int[]{3, 2, 3, 1, 2, 4, 5, 5, 6}, 4);
    }

    private int findK(int[] arr, int k) {
        MinHeapFindK minHeapFindK = new MinHeapFindK(new int[k]);
        //将前k个元素放入小顶堆
        for (int i = 0; i < k; i++) {
            minHeapFindK.offered(arr[i]);
        }
        /*
         *小于对顶元素跳过,大于堆顶元素则替换堆顶元素,重新执行下潜
         * 从k开始循环到最后(arr.length-1)
         */
        for (int i = k; i < arr.length ; i++) {
            //保留前K大的元素
            if (arr[i] >= minHeapFindK.peek()) {
                minHeapFindK.replace(arr[i]);
            }
        }
        return minHeapFindK.peek();
    }

     int[] array;
     int size;

    public MinHeapFindK(int[] array) {
        this.array = array;
        this.size = 0;
        heapify();
    }

    public MinHeapFindK() {
    }

    /*
     * 建堆:
     *   找到第一个非叶子结点
     *   执行下潜,直到没有子节点
     * */
    private void heapify() {
        //最后一个非叶子结点 size/2-1
        for (int i = size / 2 - 1; i >= 0; i--) {
            down(i);
        }
    }

    //执行下潜 parent 为需要下潜的索引,下潜到没有孩子,或者孩子都小于当前节点
    private void down(int parent) {
        //左child索引
        int leftChild = parent * 2 + 1;
        //右child索引
        int rightChild = leftChild + 1;
        int min = parent;
        if (leftChild < size && array[min] > array[leftChild]) min = leftChild;
        if (rightChild < size && array[min] > array[rightChild]) min = rightChild;
        if (min != parent) {
            //下潜并再次调用
            swap(parent, min);
            down(min);
        }
    }

    /*
     * 上浮操作
     * */
    public void up(int offered) {
        int child = size;
        //子元素索引等于0则到达了堆顶
        while (child > 0) {
            int parent = (child - 1) / 2;
            if (offered < array[parent]) {
                array[child] = array[parent];
            } else {
                break;
            }
            child = parent;
        }
        array[child] = offered;
    }

    //交换两个元素
    private void swap(int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public int peek() {
        return array[0];
    }

    /*
     * 从第一个位置移除元素,交换头尾,在移除最后一个
     * */
    public int poll() {
        int temp = array[0];
        //交换首位
        swap(0, size - 1);
        size--;
        down(0);
        return temp;
    }

    /*
     * 从指定位置移除元素,交换指定位置和尾,在移除最后一个
     * */
    public int poll(int index) {
        int temp = array[index];
        //交换首位
        swap(index, size - 1);
        size--;
        down(index);
        return temp;
    }

    /*
     * 替换堆顶部元素
     * 1.替换堆顶元素
     * 2.执行下潜,直到符合堆的特性
     * */
    public void replace(int replaced) {
        array[0] = replaced;
        down(0);
    }

    /*
     * 堆尾部添加元素
     * */
    public boolean offered(int offered) {
        if (size == array.length) {
            return false;
        }
        up(offered);
        size++;
        return true;
    }
}

1.2 求数据流中第K大的元素

比起数组,数据流是会改变的


/*
 * 小顶堆
 * */
public class MinHeapFindK2 {
    private MinHeapFindK minHeapFindK;
    public MinHeapFindK2(int k,int[]arr) {
        minHeapFindK = new MinHeapFindK(k);
        for (int i : arr) {
            add(i);
        }
    }
    public int add(int val) {
        if (minHeapFindK.size < minHeapFindK.array.length) {
            minHeapFindK.offered(val);
        } else if (val > minHeapFindK.peek())
            {
                minHeapFindK.replace(val);
            }
        return minHeapFindK.peek();
    }
    public static void main(String[] args) {
        MinHeapFindK2 minHeapFindK2=new MinHeapFindK2(3,new int[]{4,5,8,2});
        int add = minHeapFindK2.add(3);
        int add1 = minHeapFindK2.add(5);
        int add2 = minHeapFindK2.add(10);
        int add3 = minHeapFindK2.add(9);
        int add4 = minHeapFindK2.add(4);
    }
}

1.3 求数据流中的中位数

        在数据流中求中位数,可以使用一个大小为2的堆结构来实现,其中一个为小顶堆(存储较大的一半元素),另一个为大顶堆(存储较小的一半元素)。这样,小顶堆的堆顶元素总是小于或等于大顶堆的堆顶元素,并且两个堆的元素数量之差最多为1。当这两个条件满足时,大顶堆的堆顶元素就是当前流中的中位数。

具体步骤如下:

        初始化两个堆,一个大顶堆和一个小顶堆。开始时,将第一个数据元素放入任意一个堆中。

每当有新的数据元素进入时:

        将新元素添加到小顶堆中。
        如果此时小顶堆的元素个数大于大顶堆的元素个数+1,则从小顶堆取出堆顶元素(即当前最小值)并将其插入到大顶堆中,保持两个堆的元素数量平衡。
调整大顶堆使其满足大顶堆性质。
        当需要查询中位数时,直接返回大顶堆的堆顶元素即可。如果两个堆的大小相等,则这个元素就是准确的中位数;如果大顶堆比小顶堆多一个元素,则该元素也是中位数,因为所有小于它的元素都在小顶堆中,所有大于它的元素都在大顶堆中。

        通过这种方式,可以在O(log k)的时间复杂度内处理每个新来的数据点(k通常为堆的大小,即数据流中已处理的数据量的一半左右),从而实现实时计算数据流的中位数。


/*
 * 小顶堆
 * */
public class MinHeapFindMiddle {
    private MinHeapFindK rightHeap;
    private MaxHeap leftHeap;
    public MinHeapFindMiddle(int capacity) {
        rightHeap=new MinHeapFindK();
        rightHeap.array=new int[capacity];
        leftHeap=new MaxHeap();
        leftHeap.array=new int[capacity];
    }
    public void addNum(int val) {
       if(leftHeap.size==rightHeap.size){
           //如果相同就加到大顶堆,并将大顶堆最小的加到小顶堆
           leftHeap.offered(val);
           rightHeap.offered(leftHeap.poll());
       }else{
           //否则相反
           rightHeap.offered(val);
           leftHeap.offered(rightHeap.poll());
       }
    }
    /*
    * 右侧元素个数只会大于等于左侧个数
    * 两边元素一样多,取两个堆顶求平均
    * 否则取右侧堆顶元素
    * */
    public BigDecimal findMiddle(){
        if(leftHeap.size==rightHeap.size){
            BigDecimal res = new BigDecimal(leftHeap.peek() + rightHeap.peek());
            BigDecimal divide = res.divide(BigDecimal.valueOf(2));
            return divide;
        }else{
            return BigDecimal.valueOf(rightHeap.peek());
        }
    }
    public static void main(String[] args) {
        MinHeapFindMiddle minHeapFindK2=new MinHeapFindMiddle(10);
      minHeapFindK2.addNum(1);
        BigDecimal middle1 = minHeapFindK2.findMiddle();
        minHeapFindK2.addNum(2);
        BigDecimal middle2 = minHeapFindK2.findMiddle();
       minHeapFindK2.addNum(3);
        BigDecimal middle3 = minHeapFindK2.findMiddle();
       minHeapFindK2.addNum(7);
        BigDecimal middle4 = minHeapFindK2.findMiddle();
       minHeapFindK2.addNum(8);
        BigDecimal middle5 = minHeapFindK2.findMiddle();
       minHeapFindK2.addNum(9);
        BigDecimal middle6 = minHeapFindK2.findMiddle();
       minHeapFindK2.addNum(10);
        BigDecimal middle7 = minHeapFindK2.findMiddle();
       minHeapFindK2.addNum(11);
        BigDecimal middle8 = minHeapFindK2.findMiddle();
    }
}

也可以用java自带的PriorityQueue

2.树

2.1 二叉树

2.1.1 对称二叉树

public class symmetryBinaryTree {
    public static void main(String[] args) {
        TreeNode tree1 = new TreeNode(
                new TreeNode(new TreeNode(4), 2, null),
                1,
                new TreeNode(new TreeNode(5), 3, new TreeNode(6)));
        TreeNode tree2 = new TreeNode(
                new TreeNode(new TreeNode(3), 2, new TreeNode(4)),
                1,
                new TreeNode(new TreeNode(4), 2, new TreeNode(3)));
        boolean sysmmetry1 = isSysmmetry(tree1);
        boolean sysmmetry2 = isSysmmetry(tree2);
    }
   static public boolean isSysmmetry(TreeNode treeNode) {
        return check(treeNode.left, treeNode.right);
    }
    private static boolean check(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;
        }
        /*if((left !=null&&right==null) || (left ==null&&right!=null)){
            return false;
        }*/
        // left 和right 不会同时为null,所以left和right 不同时为null,但是有1个为null,那么他们两个不可能相等
        if (right == null || left == null) {
            return false;
        }
        //同时不为null,值不相等
        if (left.val != right.val) {
            return false;
        }
      return   check(left.left,right.right)&& check(left.right,right.left);
    }
}
2.1.2 二叉树的最大深度
2.1.2.1 递归解
//最大深度,递归解
public class binaryTreeDepth {
    public static void main(String[] args) {
        TreeNode tree1 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(3));

        TreeNode tree2 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(null, 3, new TreeNode(4)));
        TreeNode tree3 = new TreeNode(1);
        int maxDepth1=maxDepth(tree1);
        int maxDepth2=maxDepth(tree2);
        int maxDepth3=maxDepth(tree3);
    }
    static public int maxDepth(TreeNode treeNode) {
        if (treeNode == null) {
            return 0;
        }
        //可以不加
        /*if (treeNode.left == null && treeNode.right == null) {
            return 1;
        }*/
        int leftDepth = maxDepth(treeNode.left);
        int rightDepth = maxDepth(treeNode.right);
        return Integer.max(leftDepth, rightDepth) + 1;
    }
}
2.1.2.2 非递归解

//最大深度,非递归解
public class binaryTreeDepth2 {
    public static void main(String[] args) {
        TreeNode tree1 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(3));

        TreeNode tree2 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(null, 3, new TreeNode(4)));
        TreeNode tree3 = new TreeNode(1);
        int maxDepth1 = maxDepth(tree1);
        int maxDepth2 = maxDepth(tree2);
        int maxDepth3 = maxDepth(tree3);
    }

    static public int maxDepth(TreeNode treeNode) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        //当前节点
        TreeNode curr = treeNode;
        //最后弹栈的节点
        TreeNode pop = null;
        int max=0;
        while (curr != null || !stack.isEmpty()) {
            if (curr != null) {
                stack.push(curr);
               int size= stack.size();
               if(size>max){
                   max=size;
               }
                curr = curr.left;
            }else{
                TreeNode peek = stack.peek();
                //弹栈元素右子树等于上次弹栈的元素,说明左右都已经处理
                if(peek.right==null||peek.right==pop){
                    pop=stack.pop();
                }else{
                    curr=peek.right;
                }
            }
        }
        return max;
    }
}
2.1.2.3 层序遍历

//最大深度,层序遍历
public class binaryTreeDepth3 {
    public static void main(String[] args) {
        TreeNode tree1 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(3));

        TreeNode tree2 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(null, 3, new TreeNode(4)));
        TreeNode tree3 = new TreeNode(1);
        int maxDepth1 = maxDepth(tree1);
        int maxDepth2 = maxDepth(tree2);
        int maxDepth3 = maxDepth(tree3);
    }
    static public int maxDepth(TreeNode treeNode) {
        if(treeNode==null){
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(treeNode);
        int max=queue.size();
        int maxDepth=0;
        while (!queue.isEmpty()) {
            for (int i = 0; i < max; i++) {
                TreeNode poll = queue.poll();
                System.out.print(poll.val+"\t");
                if (poll.left != null) {
                    queue.offer(poll.left);
                }
                if (poll.right != null) {
                    queue.offer(poll.right);
                }
            }
            max = queue.size();
            System.out.println();
            maxDepth++;
        }
        return maxDepth;
    }
}
2.1.3 二叉树最小深度
2.1.3.1 递归解

//最小深度,递归解
public class binaryTreeDepth4 {
    public static void main(String[] args) {
        TreeNode tree1 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(3));

        TreeNode tree2 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(null, 3, new TreeNode(4)));
        TreeNode tree3 = new TreeNode(1);
        int minDepth1 = minDepth(tree1);
        int minDepth2 = minDepth(tree2);
        int minDepth3 = minDepth(tree3);
    }

    static public int minDepth(TreeNode treeNode) {
        if (treeNode == null) {
            return 0;
        }
        int leftDepth = minDepth(treeNode.left);
        int rightDepth = minDepth(treeNode.right);
        if (rightDepth == 0) {
            return leftDepth + 1;
        }
        if (leftDepth == 0) {
            return rightDepth + 1;
        }
        return Integer.min(leftDepth, rightDepth) + 1;
    }
}
2.1.3.2 层序遍历解
//最小深度,层序遍历解,第一个叶子结点就是最小深度
public class binaryTreeDepth5 {
    public static void main(String[] args) {
        TreeNode tree1 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(3));

        TreeNode tree2 = new TreeNode(
                new TreeNode(2),
                1,
                new TreeNode(null, 3, new TreeNode(4)));
        TreeNode tree3 = new TreeNode(1);
        int minDepth1 = minDepth(tree1);
        int minDepth2 = minDepth(tree2);
        int minDepth3 = minDepth(tree3);
    }
    static public int minDepth(TreeNode treeNode) {
        if(treeNode==null){
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(treeNode);
        int min=queue.size();
        int minDepth=0;
        while (!queue.isEmpty()) {
            min = queue.size();
            System.out.println();
            minDepth++;
            for (int i = 0; i < min; i++) {
                TreeNode poll = queue.poll();
                if(poll.left==null && poll.right==null){
                    return minDepth;
                }
                if (poll.left != null) {
                    queue.offer(poll.left);
                }
                if (poll.right != null) {
                    queue.offer(poll.right);
                }
            }
        }
        return minDepth;
    }
}

2.1.4 翻转二叉树
//翻转二叉树
public class binaryTreeInvert {
    static public TreeNode invertTree(TreeNode treeNode) {
        invert(treeNode);
       return treeNode;
    }
    static void invert(TreeNode node){
        if (node==null)return;
        TreeNode temp=node.left;
        node.left=node.right;
        node.right=temp;
        invert(node.left);
        invert(node.right);
    }
}
2.1.5 根据后缀表达式构造表达式树

public class expressionTree {
    public static void main(String[] args) {
        String[]strings1={"1","2","-","3","*"};
        TreeNode treeNode = expressionToTree(strings1);
        postOrder(treeNode);
    }
    public static TreeNode expressionToTree(String[] tokens) {
        LinkedList<TreeNode>stack=new LinkedList<>();
        for (String token : tokens) {
            switch (token) {
                case "+":
                    innerStack( stack, token);
                    break;
                case "-":
                    innerStack( stack, token);
                    break;
                case "*":
                    innerStack( stack, token);
                    break;
                case "/":
                    innerStack( stack, token);
                    break;
                default:
                    stack.push(new TreeNode(token));
            }
        }
        return stack.peek();
    }
    private static void innerStack(LinkedList<TreeNode> stack,String token){
        TreeNode right = stack.pop();
        TreeNode left = stack.pop();
        TreeNode<String> parent = new TreeNode<>(left,token,right);
        stack.push(parent);
    }
    /*
     * 后序遍历 左子树=》右子树 =》根节点
     * */
    static void postOrder(TreeNode treeNode){
        if(treeNode==null){
            return;
        }
        postOrder(treeNode.left);//左子树
        postOrder(treeNode.right);//右子树
        System.out.print(treeNode.val+"\t");//根节点
    }
}
2.1.6 根据前序,中序结果还原二叉树

//根据前序 中序结果还原二叉树
public class restoreTree {
    private TreeNode buildTree(int[] proOrder,int[]inOrder){
        if(proOrder.length==0||inOrder.length==0){
            return null;
        }
        //根元素值
        int rootVal = proOrder[0];
        TreeNode root=new TreeNode(rootVal);
        //根据根节点区分左右子树
        for (int i = 0; i < inOrder.length; i++) {
            if (inOrder[i]==rootVal){
                //0~i是左子树
                int[] inOrderLeft = Arrays.copyOfRange(inOrder, 0, i + 1);
                // i+1~inOrder.length-1是右子树
                int[] inOrderRight = Arrays.copyOfRange(inOrder, i+1, inOrder.length);
                int[] proOrderLeft = Arrays.copyOfRange(proOrder, 1, i + 1);
                int[] proOrderRight= Arrays.copyOfRange(proOrder, i + 1, inOrder.length);
                root.left = buildTree(proOrderLeft, inOrderLeft);
                root.right= buildTree(proOrderRight, inOrderRight);
                break;
            }
        }
        return root;
    }
}
 2.1.7 根据中序,后续结果还原二叉树

//根据中序 后序结果还原二叉树
public class restoreTree2 {
    private TreeNode buildTree(int[]inOrder,int[] postOrder){
        if(postOrder.length==0||inOrder.length==0){
            return null;
        }
        //根元素值
        int rootVal = postOrder[postOrder.length-1];
        TreeNode root=new TreeNode(rootVal);
        //根据根节点区分左右子树
        for (int i = 0; i < inOrder.length; i++) {
            if (inOrder[i]==rootVal){
                //0~i是左子树
                int[] inOrderLeft = Arrays.copyOfRange(inOrder, 0, i + 1);
                // i+1~inOrder.length-1是右子树
                int[] inOrderRight = Arrays.copyOfRange(inOrder, i+1, inOrder.length);
                int[] postOrderLeft = Arrays.copyOfRange(postOrder, 0, i);
                int[] postOrderRight= Arrays.copyOfRange(postOrder, i , postOrder.length);
                root.left = buildTree(inOrderLeft,postOrderLeft);
                root.right= buildTree(inOrderRight,postOrderRight);
                break;
            }
        }
        return root;
    }
}

2.2 二叉搜索树

2.2.1 验证合法二叉搜索树

左子树必须小于根节点,右子树必须大于根节点,所有的子节点也必须符合这条规则。

可以利用中序遍历,由小到大排序,若是符合条件就是一个合法的二叉搜索树。

2.2.1.1 非递归

//非递归
public class ValidityBSTree1 {
    public boolean isValidty(TreeNode node){
        TreeNode p=node;
        Integer prev=null;//上一个值
        LinkedList<TreeNode> stack=new LinkedList();
        while (p!=null || !stack.isEmpty()){
            if(p!=null){
                p=p.left;
            }else{
                TreeNode pop = stack.pop();
//                System.out.println(pop.val);
                //处理操作
                if(prev!=null&&prev>= pop.val){
                    return false;
                }
                prev=pop.val;
                p=pop.right;
            }
        }
        return true;
    }
    public ValidityBSTree1(TreeNode root) {
        this.root = root;
    }
    public ValidityBSTree1() {
    }
    TreeNode root;
    static class TreeNode {
        TreeNode left;
        TreeNode right;
        int val;
        public TreeNode(int val) {
            this.val = val;
        }
        public TreeNode(TreeNode left, TreeNode right, int val) {
            this.left = left;
            this.right = right;
            this.val = val;
        }
    }
}
2.2.1.2 递归
package org.alogorithm.tree.binarySearchTree;

import java.util.LinkedList;

//递归
public class ValidityBSTree2 {

    Integer prev = null;

    public boolean isValidty(TreeNode node) {
        if (node == null) {
            return true;
        }
        boolean validtyLeft = isValidty(node.left);
        if(!validtyLeft)return false;
        //处理值
        //上一个值必须小于等于当前值
        if (prev != null && prev >= node.val) {
            return false;
        }
        prev = node.val;
        boolean validtyRight = isValidty(node.right);
        //左右子树全部合法
        return validtyRight && validtyLeft;
    }

    public ValidityBSTree2(TreeNode root) {
        this.root = root;
    }

    public ValidityBSTree2() {
    }

    TreeNode root;

    static class TreeNode {
        TreeNode left;
        TreeNode right;
        int val;

        public TreeNode(int val) {
            this.val = val;
        }

        public TreeNode(TreeNode left, TreeNode right, int val) {
            this.left = left;
            this.right = right;
            this.val = val;
        }
    }
}
2.2.1.3 判断上下界
package org.alogorithm.tree.binarySearchTree;

//递归
public class ValidityBSTree3 {

    Integer prev = null;

    public boolean isValidty(TreeNode node) {
       return isValidty(node,null,null);
    }
    //节点必须大于min小于max
    public boolean isValidty(TreeNode node,Integer min,Integer max) {
        if(node==null){
            return true;
        }
        if((min!=null&&node.val<=min)||(max!=null&&node.val>=max)){
            return false;
        }
        boolean validtyLeft = isValidty(node.left, min, node.val);
        if(!validtyLeft)return false;
        boolean validtyRight = isValidty(node.right, node.val, max);
        return validtyRight && validtyLeft;
    }


    public ValidityBSTree3(TreeNode root) {
        this.root = root;
    }

    public ValidityBSTree3() {
    }

    TreeNode root;

    static class TreeNode {
        TreeNode left;
        TreeNode right;
        int val;

        public TreeNode(int val) {
            this.val = val;
        }

        public TreeNode(TreeNode left, TreeNode right, int val) {
            this.left = left;
            this.right = right;
            this.val = val;
        }
    }
}
2.2.2 范围求和
2.2.2.1 循环范围求和
package org.alogorithm.tree.binarySearchTree;
import java.util.LinkedList;
public class SumBSTree1 {
    Integer prev = null;
    //节点必须大于min小于max
    public Integer sum(TreeNode node, Integer min, Integer max) {
        int sum = 0;
        TreeNode p = node;
        LinkedList<TreeNode> stock = new LinkedList();
        while (p != null || !stock.isEmpty()) {
            if (p != null) {
                stock.push(p);
                p = p.left;
            } else {
                p = stock.pop();
                //如果pop.val已经大于上限,则不需要遍历右子树
                if(p.val>max){
                    break;
                }
                if (p.val >= min && p.val <= max) {
                    sum += p.val;
                }
                p = p.right;
            }
        }
        return sum;
    }
    public SumBSTree1(TreeNode root) {
        this.root = root;
    }
    public SumBSTree1() {
    }
    TreeNode root;
    static class TreeNode {
        TreeNode left;
        TreeNode right;
        int val;
        public TreeNode(int val) {
            this.val = val;
        }
        public TreeNode(TreeNode left, TreeNode right, int val) {
            this.left = left;
            this.right = right;
            this.val = val;
        }
    }
}
2.2.2.2 上下限递归

import java.util.LinkedList;
public class SumBSTree1 {
    Integer prev = null;
    //节点必须大于min小于max
    public Integer sum(TreeNode node, Integer min, Integer max) {
        int sum = 0;
        TreeNode p = node;
        LinkedList<TreeNode> stock = new LinkedList();
        while (p != null || !stock.isEmpty()) {
            if (p != null) {
                stock.push(p);
                p = p.left;
            } else {
                p = stock.pop();
                //如果pop.val已经大于上限,则不需要遍历右子树
                if(p.val>max){
                    break;
                }
                if (p.val >= min && p.val <= max) {
                    sum += p.val;
                }
                p = p.right;
            }
        }
        return sum;
    }
    public SumBSTree1(TreeNode root) {
        this.root = root;
    }
    public SumBSTree1() {
    }
    TreeNode root;
    static class TreeNode {
        TreeNode left;
        TreeNode right;
        int val;
        public TreeNode(int val) {
            this.val = val;
        }
        public TreeNode(TreeNode left, TreeNode right, int val) {
            this.left = left;
            this.right = right;
            this.val = val;
        }
    }
}

2.2.3 根据前序遍历还原二叉搜索树

2.2.3.1 递归插入
public class BstFromPreorder1 {
    TreeNode root;
    public BstFromPreorder1(TreeNode root) {
        this.root = root;
    }
    public BstFromPreorder1(int[] arr) {
        //索引0为根节点
        TreeNode treeNode = new TreeNode(arr[0]);
        for (int i = 1; i < arr.length; i++) {
            int val = arr[i];
            this.root = insert(root, val);
        }
    }
    private TreeNode insert(TreeNode node,int val) {
        if (node == null) {
            return new TreeNode(val);
        }
        if(val < node.val){
        //如果插入值小于当前节点值,则递归插入到左子树
            node.left=insert(node.left,val);
        }else if(val>node.val){
            //如果插入值大于当前节点值,则递归插入到右子树
            node.right=insert(node.right,val);
        }
        return node;
}
    static class TreeNode {
        TreeNode left;
        TreeNode right;
        int val;
        public TreeNode(int val) {
            this.val = val;
        }
        public TreeNode(TreeNode left, TreeNode right, int val) {
            this.left = left;
            this.right = right;
            this.val = val;
        }
    }
}
2.2.3.2 上限法
public class BstFromPreorder2 {
    TreeNode root;
    public BstFromPreorder2(TreeNode root) {
        this.root = root;
    }
    public BstFromPreorder2(int[] arr) {
      this.root=  insert(arr,Integer.MAX_VALUE);
    }

    /*
    上限法5,1,7,10,12
        1.遍历数组中每一个值,根据值创建节点
            -每个节点若成功创建都有左孩子上限,右孩子上限
         2.处理下一个值时,如果超过此上限,那么
            -将 null 作为上个节点的孩子
            -不能创建节点对象
            -直到不超过上限为止
        3.重复1.2.两步
*/
    int index = 0;
    private TreeNode insert(int[] arr, int max) {
        if (index == arr.length) {
            return null;
        }
        int val = arr[index];
        //如果大于上限返回null作为上一个节点的孩子
        if (val > max) {
            return null;
        }
        //如果创建了节点
        TreeNode treeNode = new TreeNode(val);
        index++;
        //如果左右都满了就返回该节点
        //左孩子上限就是本身的val
        treeNode.left = insert(arr, val);
        //右孩子上限还是max
        treeNode.right = insert(arr, max);
        return treeNode;

    }
    static class TreeNode {
        TreeNode left;
        TreeNode right;
        int val;
        public TreeNode(int val) {
            this.val = val;
        }
        public TreeNode(TreeNode left, TreeNode right, int val) {
            this.left = left;
            this.right = right;
            this.val = val;
        }
    }
}

1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值