递归、树

面试题 17.12. BiNode

在这里插入图片描述

题目明确要求转化操作应是原址的,因此使用中序遍历保存所有节点值,在构建链表的做法显然是不行的考虑对树中的节点逐一遍历,并进行转化.参照判断二叉搜索树一文,我们可以保存当前节点的后继节点,然后逐一进行更改即可.其中为了方便保存后继节点,我们使用右中左的中序遍历序列.

class Solution {
    TreeNode next = null;
    //中序遍历每一节点,将当前节点的right设为其后继节点,left置空
    public TreeNode convertBiNode(TreeNode root) {
        if( root == null)
            return null;
        convertBiNode(root.right);
        
        root.right = next; //当前节点right 置为后继节点
        next = root;       //更新后继节点;
        TreeNode left = root.left;
        root.left = null;
        if(left == null)  //如果当前节点的左子节点为空,直接返回当前值.
            return root;
        else 
            return convertBiNode(left);
    }
}
class Solution {
    TreeNode  head = new TreeNode(-1);
    TreeNode pre = head;
    public TreeNode convertBiNode(TreeNode root) {
        inOrder(root);
        return head.right;
    }

    private void inOrder(TreeNode root) {
        if (root == null) return;
        inOrder(root.left);
        pre.right = root;  //gengxin
        pre = root;  //指向下一个
        root.left = null;
        inOrder(root.right);
    } 
}

面试题 16.11. 跳水板

在这里插入图片描述

  • new int[0]和null还不一样
	public int[] divingBoard(int shorter, int longer, int k) {
        if(k == 0)
            return new int[0];
            //new int[0]和null还不一样
        if(shorter == longer){
            return new int[]{shorter * k};
        }
        int[] ans = new int[k+1];
        for(int i = 0; i <= k; i++){
            ans[i] = shorter*(k - i) + longer * i;
        }
        return ans;
    }

在这里插入图片描述

当你在思考这个问题的时候,就将最初的 n 个盘子从 A 移到 C 的问题,转化成了将 n - 1 个盘子从 A 移到 C 的问题, 依次类推,直至转化成 1 个盘子的问题时,问题也就解决了。这就是分治的思想。

class Solution {
    public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
        int n = A.size();
        move(n,A,B,C);
    }

    private void move(int n, List<Integer> A, List<Integer> B, List<Integer> C)
    {
        if(n == 1){
            C.add(A.remove(A.size()-1));
            return;
        }
        move(n - 1, A, C, B); //把A中 n-1个盘子通过C移动到B;
        C.add(A.remove(A.size() - 1)); //A中最大盘子移动到C
        move(n - 1, B, A, C); //把B中n - 1个盘子通过A移动到C
        return;
    }
}

面试题 04.12. 求和路径

在这里插入图片描述

class Solution {
   
    private int ret = 0;

    public int pathSum(TreeNode root, int sum) {
        preOrder(root, sum);
        return ret;
    }

    /**
     * 题目要求可以从每个结点出发,每个结点调用一次dfs
     *
     * @param root
     * @param sum
     */
    private void preOrder(TreeNode root, int sum) {
        if (root == null) {
            return;
        }
        dfs(root, sum);
        preOrder(root.left, sum);
        preOrder(root.right, sum);
    }

    /**
     * 从root结点出发,求路径和等于sum路径数
     *
     * @param root
     * @param sum
     */
    private void dfs(TreeNode root, int sum) {
        if (root == null) {
            return;
        }
        if (root.val == sum) {
            ret++;
        }
        dfs(root.left, sum - root.val);
        dfs(root.right, sum - root.val);
    }
}
public int pathSum(TreeNode root, int sum) {
        if (root == null) {
            return 0;
        }

        //               每个节点都遍历                               具体求解每一个节点                   
        return pathSum(root.left, sum) + pathSum(root.right, sum) + helper(root, sum);
    }
    private int helper(TreeNode root, int sum) {
        if (root == null) {
            return 0;
        }
        int ret = sum == root.val ? 1 : 0;
        sum -= root.val;
        return helper(root.left, sum) + helper(root.right, sum) + ret;
    }

面试题 04.10. 检查子树

在这里插入图片描述

  • 是值相等,而不是原节点砍断
 	public boolean checkSubTree(TreeNode t1, TreeNode t2) {
        if(t2 == null)
            return true;
        if(t1 == null)
            return false;
        if(t1.val == t2.val){
            return checkSubTree(t1.left, t2.left) && checkSubTree(t1.right, t2.right);
        }
        return checkSubTree(t1.left, t2) || checkSubTree(t1.right, t2);
    }

祖先类的模板题目

模板

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL){
            return NULL;
        }
        if(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 root;            //找到
        }
        if(left==NULL&&right==NULL){
            return NULL;
        }
        return left==NULL? right:left; //找到可能的节点返回该节点
    }
};

在这里插入图片描述

面试题 04.08. 首个共同祖先

在这里插入图片描述

//先序遍历
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null){
            return null;
        }
        //如果找到了则返回
        if(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 root;
        } 
        if(left == null && right == null){
            return null;
        }
        return left == null ? right : left;
    }

865. 具有所有最深节点的最小子树

1123. 最深叶节点的最近公共祖先

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 所有最深节点的最小子树。其实就是首先找到最深的节点,然后找到这些节点的公共父节点(最近的那个)
	public TreeNode subtreeWithAllDeepest(TreeNode root) {
        int deep=deepth(root, 0);

        return lca(root,deep, 1);
    }
    private int deepth(TreeNode root,int curr ){//寻找最大深度
        if(root==null){
            return curr;
        }
        return Math.max(deepth(root.left,curr+1),deepth(root.right,curr+1));
    }
    private TreeNode lca (TreeNode root,int deep,int curr){
        if(root==null){
            return null;
        }
        if(curr == deep){  //当前节点已经是最大深度
            return root;
        }
        TreeNode left = lca(root.left,deep,curr+1);
        TreeNode right= lca(root.right,deep,curr+1);
        if(left != null && right!= null){
            return root;
        }
        if(left==null&&right== null){
            return null;
        }
        return left== null? right:left;

    }

剑指 Offer 68 - II. 二叉树的最近公共祖先

	public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null)
            return null;
        if(root == q || root == p){
            return root;
        }

        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        if(left != null && right!= null )
            return root;
        if(left == null && right == null)
            return null;
        return left == null ? right: left;
    }

面试题 04.06. 后继者

  1. 首先要确定中序遍历的后继:
  • 如果该节点有右子节点, 那么后继是其右子节点的子树中最左端的节点
  • 如果该节点没有右子节点, 那么后继是离它最近的祖先, 该节点在这个祖先的左子树内.

1)求后继节点
1.1)如果有右孩子,后继肯定是右孩子的最左节点
1.2)如果没有右孩子,那说明在中序序列中,这是某个左子树的最右一个节点,下一跳就会回到它的头。

  • 思路: 找到第一个比p大的值
	public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        TreeNode res = null;
        TreeNode cur = root;
        //找到第一个比p大的值
        while(cur != null){
            if(cur.val <= p.val)  //当前值比查找值小,进入比他大的区域  右侧
                cur = cur.right;
            else{  //  当前值比查找值大。进入小于的区域,且保留比他大的值
                res = cur;
                cur = cur.left;
            }
        }
        return res;
    }
 public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        if(root==null || p==null){
            return null;
        }
        if(root.val<=p.val){
            TreeNode right = inorderSuccessor(root.right,p);
            return right;
        }else{
            TreeNode left= inorderSuccessor(root.left,p);
            return (left!=null)?left:root;
        }

    }

面试题 04.05. 合法二叉搜索树

  • 如果该二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;它的左右子树也为二叉搜索树。
public boolean isValidBST(TreeNode root) {
        
        return helper(root, null,  null);

    }

    private boolean helper(TreeNode root, Integer lower, Integer upper){
        if(root == null)
            return true;
        int val = root.val;
        if(lower != null && val <= lower)
            return false;
        if(upper != null && val >= upper){
            return false;
        }
        if(!helper(root.left, lower, val)){
            return false;
        }
        if(!helper(root.right, val, upper))
            return false;
        return true;
    }
class Solution {
    //中序遍历,判断有序
    TreeNode pre;
    public boolean isValidBST(TreeNode root) {
        if(root == null)
            return true;
        if(!isValidBST(root.left))
            return false;

        if(pre!=null && root.val <= pre.val)
            return false;
        pre = root;
        if(!isValidBST(root.right))
            return false;         
        return true;    
    }
}
class Solution {
    //中序遍历,判断有序
    ArrayList<Integer> list = new ArrayList<Integer>();
    public boolean isValidBST(TreeNode root) {
        inOrder(root);
        if(list.size() <=1)
            return true;
        for(int i = 0; i < list.size() - 1; i++){
            if(list.get(i) >= list.get(i + 1))
                return false;
        }
        
        return true;
    }

    private void inOrder(TreeNode root){
        if(root == null){
            return;
        }
        inOrder(root.left);
        list.add(root.val);
        inOrder(root.right);
    }
}

面试题 04.04. 检查平衡性

在这里插入图片描述

public boolean isBalanced(TreeNode root) {
        if(root == null)
            return true;
        return Math.abs(getDeepth(root.left) - getDeepth(root.right)) < 2 && isBalanced(root.left) && isBalanced(root.right);
    }

    private int getDeepth(TreeNode node){
        if(node == null)
            return 0;
        return Math.max(getDeepth(node.left), getDeepth(node.right)) + 1;
    }

面试题 04.03. 特定深度节点链表

在这里插入图片描述

  • 用一个size()代替que2就行了
public ListNode[] listOfDepth(TreeNode root) {
        ListNode[] ans = new ListNode[getDeepth(root)];
        Queue<TreeNode> que1 = new ArrayDeque<>();
        Queue<TreeNode> que2 = new ArrayDeque<>();
        que1.add(root);
        int deep = 0;
        while(!que1.isEmpty() || !que2.isEmpty()){
            ListNode dummy = new ListNode(0);
            ListNode cur = dummy;
            while(!que1.isEmpty()){
                TreeNode temp = que1.poll();
                cur.next = new ListNode(temp.val);
                cur = cur.next;
                if(temp.left != null){
                    que2.add(temp.left);
                }
                if(temp.right != null){
                    que2.add(temp.right);
                }
            }
            ans[deep] = dummy.next;
            deep++;
            while(!que2.isEmpty()){
                que1.add(que2.poll());
            }
        }
        return ans;
    }
    private int getDeepth(TreeNode root){
        if(root == null)
            return 0;
        return Math.max(getDeepth(root.left), getDeepth(root.right)) + 1;
    }

面试题 04.02. 最小高度树

在这里插入图片描述

	public TreeNode sortedArrayToBST(int[] nums) {
        return buildTree(nums, 0, nums.length - 1);
    }

    private TreeNode buildTree(int[] nums, int left, int right){
        if(left > right){
            return null;
        }
        int loc = left + (right - left)/2;
        TreeNode root = new TreeNode(nums[loc]);
        root.left = buildTree(nums, left, loc - 1);
        root.right = buildTree(nums, loc + 1, right);
        return root;
    }

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

在这里插入图片描述

	public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null)
            return null;
        if(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;
        if(left != null && right != null)
            return root;
        return left == null ? right:left;
    }

剑指 Offer 55 - II. 平衡二叉树

在这里插入图片描述

  • 先序遍历 + 判断深度 (从顶至底)
    此方法容易想到,但会产生大量重复计算,时间复杂度较高。
    思路是构造一个获取当前子树的深度的函数 depth(root) (即 面试题55 - I. 二叉树的深度 ),通过比较某子树的左右子树的深度差 abs(depth(root.left) - depth(root.right)) <= 1 是否成立,来判断某子树是否是二叉平衡树。若所有子树都平衡,则此树平衡。

  • 算法流程:
    1.

public boolean isBalanced(TreeNode root) {
        if(root == null)
            return true;
        return Math.abs(deepth(root.left) - deepth(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
    }

    private int deepth(TreeNode root){
        if(root == null)
            return 0;
        return Math.max(deepth(root.left), deepth(root.right)) + 1;
    }
  • 后序遍历 + 剪枝 (从底至顶)
    此方法为本题的最优解法,但剪枝的方法不易第一时间想到。
    思路是对二叉树做后序遍历,从底至顶返回子树深度,若判定某子树不是平衡树则 “剪枝” ,直接向上返回。
    在这里插入图片描述
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;// 返回最大深度,或者返回不平衡
    }

剑指 Offer 55 - I. 二叉树的深度

	public int maxDepth1(TreeNode root) {
        if(root == null)
            return 0;
        LinkedList<TreeNode> list = new LinkedList<>();
        list.add(root);
        int size = list.size();
        int depth = 0;
        while(!list.isEmpty()){
            while(size > 0){
                TreeNode temp = list.pop();
                if(temp.left!=null)
                    list.add(temp.left);
                if(temp.right!=null)
                    list.add(temp.right);
                size--;
            }
            depth++;
            size = list.size();
        }
        return depth;
    }
	public int maxDepth (TreeNode root) {
        // write code here
        if(root == null) return 0;
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }

剑指 Offer 54. 二叉搜索树的第k大节点

在这里插入图片描述

class Solution {
    private int count = 0;
    TreeNode ans = null;
    public int kthLargest(TreeNode root, int k) {
        dfs(root, k);
        return ans.val;
    }

    private void dfs(TreeNode root,int k){
        if(root == null)
            return;
        dfs(root.right, k);
        if(k == count){
            return;
        } 
        count ++;
        if(count==k){
            ans = root;
        }
        dfs(root.left, k);
    }   
}

剑指 Offer 37. 序列化二叉树

 // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root == null)
            return "[]";

        StringBuilder sb = new StringBuilder("[");
        Queue<TreeNode> que = new LinkedList<>();
        que.add(root);
        while(!que.isEmpty()){
            TreeNode temp = que.poll();
            if(temp != null){
                sb.append(temp.val+",");
                que.add(temp.left);
                que.add(temp.right);
            } else{
                sb.append("null,");
            }
        }
        sb = sb.deleteCharAt(sb.length() - 1);
        sb.append("]");
        return sb.toString();

    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data.equals("[]"))
            return null;
        String[] values = data.substring(1, data.length() - 1).split(",");
        Queue<TreeNode> que = new ArrayDeque<>();
        if(values[0].equals("null"))
            return null;
        TreeNode root = new TreeNode(Integer.parseInt(values[0]));
        que.add(root);
        int i = 1;
        while(!que.isEmpty()){
            TreeNode temp = que.poll();
            if(!values[i].equals("null")){
                temp.left = new TreeNode(Integer.parseInt(values[i]));
                que.add(temp.left);
            }
            i++;  //判断当前是否是null,不是空也要下一个,是空也要下一个
            if(!values[i].equals("null")){
                temp.right = new TreeNode(Integer.parseInt(values[i]));
                que.add(temp.right);
            }
            i++;
        }
        return root;
    }

剑指 Offer 34. 二叉树中和为某一值的路径

在这里插入图片描述

class Solution {
    List<List<Integer>> list = new LinkedList<>();
    LinkedList<Integer> ans = new LinkedList<>();
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        if(root == null)
            return list;
        dfs(root, target);
        return list;
    }

    private void dfs(TreeNode root, int target){
        if(root == null){
            return;
        }
        target -= root.val;
        ans.add(root.val);

        if(target == 0 && root.left == null && root.right == null){
            list.add(new LinkedList(ans));
            //return;   不能return,要不然就没有remove
        }
        dfs(root.left, target);
        dfs(root.right, target);
        ans.removeLast(); 
    }
}

剑指 Offer 32 - III. 从上到下打印二叉树 III

在这里插入图片描述

public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null)
            return res;
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        stack1.push(root);
        while(!stack1.isEmpty() || !stack2.isEmpty()){
            List<Integer> path = new ArrayList<>();
            while(!stack1.isEmpty()){
                TreeNode temp = stack1.pop();
                path.add(temp.val);
                
                if(temp.left!=null){
                    stack2.push(temp.left);
                }
                if(temp.right!= null){
                    stack2.push(temp.right);
                }
            }
            if(path.size() > 0 )
                res.add(path);

            List<Integer> path2 = new ArrayList<>();
            while(!stack2.isEmpty()){
                TreeNode temp = stack2.pop();
                path2.add(temp.val);
                
                if(temp.right!= null){
                    stack1.push(temp.right);
                }
                if(temp.left!=null){
                    stack1.push(temp.left);
                }
                
            }
            if(path2.size() > 0)
            res.add(path2);
        }
        return res;

    }
public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null)
            return res;
        Queue<TreeNode> que = new ArrayDeque<>();
        que.add(root);
        while(!que.isEmpty()){
            LinkedList<Integer> path = new LinkedList<>();
            for(int i = que.size(); i > 0; i--){
                TreeNode temp = que.poll();
                if(res.size()%2 == 0) 
                    path.addLast(temp.val);
                else
                    path.addFirst(temp.val);
                if(temp.left != null)
                    que.add(temp.left);
                if(temp.right != null)
                    que.add(temp.right);
            }
            res.add(path);
        }
        return res;

    }

剑指 Offer 32 - I. 从上到下打印二叉树

在这里插入图片描述

public int[] levelOrder(TreeNode root) {
        ArrayList<Integer> path = new ArrayList<>();
        Queue<TreeNode> que = new ArrayDeque<>();
        if(root == null)
            return new int[0];
        que.add(root);
        while(!que.isEmpty()){
            for(int i = que.size(); i > 0; i--){
                TreeNode temp = que.poll();
                path.add(temp.val);
                if(temp.left != null)
                    que.add(temp.left);
                if(temp.right != null)
                    que.add(temp.right);
            }
        }
        Integer[] arr = path.toArray(new Integer[path.size()]);
        int[] res = new int[arr.length];
        for(int i = 0; i < arr.length; i ++)
            res[i] = arr[i];
        return res;
    }

剑指 Offer 28. 对称的二叉树

在这里插入图片描述

public boolean isSymmetric(TreeNode root) {
        if(root == null)
            return true;
        return dfs(root.left, root.right);
    }

    private boolean dfs(TreeNode left, TreeNode right){
        if(left == null && right == null)
            return true;
        if(left==null && right != null)
            return false;
        if(left != null && right == null)
            return false;
        if(left.val != right.val)
            return false;

		//上三种情况合在一起 
        //if(left == null || right == null || left.val != right.val) return false;
        return dfs(left.left, right.right) && dfs(left.right, right.left);
    }

剑指 Offer 26. 树的子结构

在这里插入图片描述
遍历每一个节点

	public boolean isSubStructure(TreeNode A, TreeNode B) {
        if(A == null || B == null)
            return false;
        return dfs(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
    }

    private boolean dfs(TreeNode A, TreeNode B){
        if( B == null)  //B子结构
            return true;
        if(A == null || A.val != B.val)
            return false;
        return dfs(A.left, B.left) && dfs(A.right, B.right);
    }

50. Pow(x, n)

剑指 Offer 16. 数值的整数次方

在这里插入图片描述

public double myPow(double x, int n) {
        long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }

    public double quickMul(double x, long N) {
        if (N == 0) {
            return 1.0;
        }
        double y = quickMul(x, N / 2);
        return N % 2 == 0 ? y * y : y * y * x;
    }
public double myPow(double x, int n) {
        long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }

    public double quickMul(double x, long N) {
        double ans = 1.0;
        // 贡献的初始值为 x
        double x_contribute = x;
        // 在对 N 进行二进制拆分的同时计算答案
        while (N > 0) {
            if (N % 2 == 1) {
                // 如果 N 二进制表示的最低位为 1,那么需要计入贡献
                ans *= x_contribute;
            }
            // 将贡献不断地平方
            x_contribute *= x_contribute;
            // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
            N /= 2;
        }
        return ans;
    }

剑指 Offer 10- II. 青蛙跳台阶问题 和剑指 Offer 10- I. 斐波那契数列 一样的解法

在这里插入图片描述

// public int numWays(int n) {
    //     if(n == 0)
    //         return 1;
    //     if(n == 1)
    //         return 1;
    //     if( n == 2)
    //         return 2;
    //     return numWays(n - 1)%1000000007 + numWays(n - 2)%1000000007; //可以跳一个台阶也可以跳两个台阶
    // }

    public int numWays(int n) {
        int a = 1, b = 1, sum = 0; 
        for(int i = 1; i < n; i++){
            sum = (a + b) % 1000000007;
            a = b;
            b = sum;
        }
        return b;
    }

剑指 Offer 07. 重建二叉树

在这里插入图片描述

class Solution {
    private Map<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //建立索引,根据前序遍历能快速定位中序位置
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i], i);
        }
        return rebulidTree(preorder, 0, 0, preorder.length - 1);
    }

    private TreeNode rebulidTree(int[] preorder, int left, int root, int right){
        if(left > right)
            return null;
        TreeNode node = new TreeNode(preorder[root]);
        int loc = map.get(preorder[root]);
        node.left = rebulidTree(preorder, left, root + 1, loc - 1);
        node.right = rebulidTree(preorder, loc + 1, root + loc - left + 1, right); //root的位置加上左边节点的个数就是右子数的第一个节点。
        return node;
    } 
}

94. 二叉树的中序遍历

class Solution {
    ArrayList<Integer> list = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root == null)
            return list;
        inorderTraversal(root.left);
        list.add(root.val);
        inorderTraversal(root.right);
        return list;
    }
}

回溯模板

递归{
    递归出口;
    for(int i = 1;i<=n;i++){
    	add(i);
    	进入递归;
   		remove(i);
	}
}

105从前序和中序遍历序列构造二叉树

在这里插入图片描述
从上可以发现前序和中序, 右子树的下标位置相同

  • 第一步:确定前序遍历的根节点在中序遍历的位置索引
  • 第二步:可以根据中序遍历的位置确定左子树的个数
  • 第三步:参数中的前序遍历的位置可以根据左子树的个数进行确定,中序遍历的位置可以根据定位的根节点进行确定。
	//根据值能找到索引位置
    Map<Integer, Integer> map = new HashMap<>();
    //通过前序确定中序的位置,然后才能继续划分
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i],i);
        }
        return reBuildTree(preorder, 0, preorder.length - 1, 0, inorder.length - 1);
    }

    private TreeNode reBuildTree(int[] preorder, int pre_start, int pre_end,int in_start,int in_end){

        if(pre_start > pre_end || in_start > in_end){
            return null;
        }

        TreeNode root = new TreeNode(preorder[pre_start]);
        int index = map.get(preorder[pre_start]);

        //左子树中的个数
        int num = index - in_start; //根据中序遍历获得左子树个数
        

        //根据左子树的个数逐个查找
        root.left = reBuildTree(preorder,pre_start + 1, pre_start + num, in_start, index - 1);

        //index定位的是中序中的数
        root.right = reBuildTree(preorder,pre_start + num + 1, pre_end, index + 1, in_end);
        return root;
    }

106. 从中序与后序遍历序列构造二叉树

在这里插入图片描述
从上可以发现后序和中序, 左子树树的下标位置相同

  • 第一步:确定后序遍历的根节点在中序遍历的位置索引
  • 第二步:可以根据中序遍历的位置确定右子树的个数(操作中序序列)
  • 第三步:参数中的后序遍历的位置可以根据左子树的个数进行确定,中序遍历的位置可以根据定位的根节点进行确定。
	Map<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //建立hash表,减少搜索时间
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i],i);
        }
        return reBuildTree(postorder,0, inorder.length - 1, 0, postorder.length - 1);
    }

    private TreeNode reBuildTree(int[] postorder, int in_start, int in_end, int post_start, int post_end){
        if(in_start > in_end || post_start > post_end){
            return null;
        }
        TreeNode root = new TreeNode(postorder[post_end]);
        int index = map.get(postorder[post_end]);
        int num = in_end - index;
        root.right = reBuildTree(postorder, index + 1, in_end, post_end - num, post_end - 1);
        root.left = reBuildTree(postorder,in_start, index - 1, post_start, post_end - num - 1);
        return root;
    }

113. 路径总和 II

在这里插入图片描述
在这里插入图片描述

	List<List<Integer>> list = new LinkedList<>();
    LinkedList<Integer> ans = new LinkedList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        if(root == null){
            return list;
        }
        ans.add(root.val);
        if(targetSum - root.val == 0 && root.left == null && root.right == null){
            list.add(new LinkedList(ans));
        }
        pathSum(root.left, targetSum - root.val);
        pathSum(root.right, targetSum - root.val);
        ans.removeLast();
        return list;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
递归(Recursion Tree)是一种可视化递归的方式,它通过将递归转化为形结构来帮助我们更好地理解递归的执行过程和时间复杂度。 在递归中,每次递归调用都会产生一个新的子问题,直到达到基本情况,然后逐级返回结果。这样的递归过程可以用一棵来表示,其中每个节点代表一个递归调用,子节点代表对应的子问题,叶子节点代表基本情况的返回值。 举个例子,假设我们要求一个数组的所有子集,可以使用如下的递归: ``` void subsets(vector<int>& nums, int start, vector<int>& subset, vector<vector<int>>& res) { res.push_back(subset); for (int i = start; i < nums.size(); i++) { subset.push_back(nums[i]); subsets(nums, i+1, subset, res); subset.pop_back(); } } vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> res; vector<int> subset; subsets(nums, 0, subset, res); return res; } ``` 我们可以将递归过程可视化为下面的递归: ``` [] / | \ [1] [2] [3] / \ / \ | [1,2] [1,3] [2,3] [3,4] [1,2,3] / \ | [1,2,3] [1,3,4] [2,3,4] ``` 其中,[]代表一个子集,每个节点代表一次递归调用,左子节点代表将当前元素加入子集,右子节点代表不将当前元素加入子集。当递归到数组末尾时,就返回一个空子集。 通过递归,我们可以更好地理解递归的执行过程,并且可以根据递归来分析时间复杂度。在上面的例子中,递归的深度为数组的长度N,每个节点会被访问一次,因此时间复杂度为O(2^N)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值