【剑指offer2】 chap8 树

八、树

1、基础知识

树的定义

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

BFS

    public List<Integer> bfs(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        if (root != null) queue.offer(root);

        List<Integer> result = new ArrayList<>();
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            result.add(node.val);

            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        return result;
    }

二叉树DFS

(各有两种方法:递归+栈)

中序遍历

//中序遍历-递归
public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> nodes = new LinkedList<>();
    dfs(root, nodes);
    return nodes;
}
private void dfs(TreeNode root, List<Integer> nodes) {
    if (root != null) {
        dfs(root.left, nodes);
        nodes.add(root.val);
        dfs(root.right, nodes);
    }
}
//中序遍历-栈
public List<Integer> inorderTraversal2(TreeNode root) {
    List<Integer> nodes = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();

    TreeNode curr = root;
    while (curr != null || !stack.isEmpty()) {
        while (curr != null) {
            stack.push(curr);
            curr = curr.left;
        }
        curr = stack.pop();
        nodes.add(curr.val);
        curr = curr.right;
    }
    return nodes;
}

前序遍历

//前序遍历-栈
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> nodes = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();

    TreeNode curr = root;
    while (curr != null || !stack.isEmpty()) {
        while (curr != null) {
            //注意差别
            nodes.add(curr.val);//!!!!!!!!!!!!!!!!!!!!!!!!
            stack.push(curr);
            curr = curr.left;
        }
        curr = stack.pop();
//      nodes.add(curr.val);
        curr = curr.right;
    }
    return nodes;
}

后序遍历

2、基本题型

二叉树DFS

剑指 Offer II 047. 二叉树剪枝        后序遍历递归

public TreeNode pruneTree(TreeNode root) {
    if (root == null) {
        return null;
    }
    //后序遍历
    root.left = pruneTree(root.left);
    root.right = pruneTree(root.right);
    if (root.left == null && root.right == null && root.val == 0) {
        return null;
    }
    return root;
}

剑指 Offer II 048. 序列化与反序列化二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) {
            return "#";
        }
        String leftStr = serialize(root.left);
        String rightStr = serialize(root.right);
        return String.valueOf(root.val) + "," + leftStr + "," + rightStr;
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        String[] nodeStrs = data.split(",");
        int[] i = {0};
        return dfs(nodeStrs, i);
    }
    private TreeNode dfs(String[] strs, int[] i){
        String str = strs[i[0]];
        i[0]++;

        if(str.equals("#")){
            return null;
        }

        TreeNode node = new TreeNode(Integer.valueOf(str));
        node.left = dfs(strs,i);
        node.right = dfs(strs,i);
        return node;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

剑指 Offer II 049. 从根节点到叶节点的路径数字之和

public int sumNumbers(TreeNode root) {
    return dfs(root, 0);
}

private int dfs(TreeNode root, int path) {
    if (root == null) return 0;

    path = path * 10 + root.val;

    if (root.left == null && root.right == null) {
        return path;
    }
    return dfs(root.left, path) + dfs(root.right, path);
}

剑指 Offer II 050. 向下的路径节点之和    前缀和+递归+回溯(+1递归后需要-1)

private int dfs(TreeNode root, int sum, Map<Integer, Integer> map, int path) {
    if (root == null) {
        return 0;
    }

    path += root.val;

    int count = map.getOrDefault(path - sum, 0);
    map.put(path, map.getOrDefault(path, 0) + 1);

    count += dfs(root.left, sum, map, path);
    count += dfs(root.right, sum, map, path);

    map.put(path, map.get(path) - 1);
    return count;
}

剑指 Offer II 051. 节点之和最大的路径

class Solution {
    public int maxPathSum(TreeNode root) {
        int[] maxSum = {Integer.MIN_VALUE};

        dfs(root, maxSum);

        return maxSum[0];
    }

    private int dfs(TreeNode root, int[] maxSum) {
        if (root == null) return 0;

        int[] maxSumLeft = {Integer.MIN_VALUE};
        int left = Math.max(0, dfs(root.left, maxSumLeft));

        int[] maxSumRight = {Integer.MIN_VALUE};
        int right = Math.max(0, dfs(root.right, maxSumRight));

        maxSum[0] = Math.max(maxSumLeft[0], maxSumRight[0]);
        maxSum[0] = Math.max(maxSum[0], root.val + left + right);

        return root.val + Math.max(left, right);
    }
}

二叉搜索树

中序遍历(栈)

剑指 Offer II 052. 展平二叉搜索树

剑指 Offer II 053. 二叉搜索树中的中序后继

剑指 Offer II 054. 所有大于等于节点的值之和

剑指 Offer II 055. 二叉搜索树迭代器  (curr + stack)

剑指 Offer II 056. 二叉搜索树中两个节点之和

TreeSet和TreeMap

TreeSet:   set.floor(num) <=   set.upper(num) >=

剑指 Offer II 057. 值和下标之差都在给定的范围内

 

class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        TreeSet<Long> set = new TreeSet<>();
        for (int i = 0; i < nums.length; i++) {
            //在i-k~i的范围内找到小于等于nums[i]的最大的数,检验差值是否符合要求
            Long lower = set.floor((long) nums[i]);
            if (lower != null && lower >= (long) nums[i] - t) {
                return true;
            }
            //在i-k~i的范围内找到小于等于nums[i]的最大的数,检验差值是否符合要求
            Long upper = set.ceiling((long) nums[i]);
            if (upper != null && upper <= (long) nums[i] + t) {
                return true;
            }
            //都没有的话,就把数添加到集合里
            set.add((long) nums[i]);
            //把<=i - k 的都删掉
            if (i >= k) {
                set.remove((long) nums[i - k]);
            }
        }
        return false;
    }
}

TreeMap

Map.Entry<Integer, Integer> event = events.floorEntry(start);

剑指 Offer II 058. 日程表

class MyCalendar {
    private TreeMap<Integer, Integer> events;
    public MyCalendar() {
        events = new TreeMap<Integer, Integer>();
    }
    
    public boolean book(int start, int end) {
        Integer lStart = events.floorKey(start);
        if (lStart != null && events.get(lStart) > start) {
            return false;
        }

        Integer rStart = events.ceilingKey(start);
        if (rStart != null && rStart < end) {
            return false;
        }
        events.put(start, end);
        return true;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值