【算法題型總結】--四、樹

一、NC117 合併二叉樹java

public TreeNode mergeTrees (TreeNode t1, TreeNode t2)node

 

 

public class Solution {
    /**
     * 
     * @param t1 TreeNode類 
     * @param t2 TreeNode類 
     * @return TreeNode類
     */
    public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
        if (t1 == null && t2 == null) return null;
        if (t1 == null || t2 == null) return t1 == null ? t2 : t1;
        // 此時 t一、t2 均不爲 null
        // 合併節點的值
        t1.val = t1.val + t2.val;
        // 合併左子樹
        t1.left = mergeTrees(t1.left, t2.left);
        // 合併右子樹
        t1.right = mergeTrees(t1.right, t2.right);
        return t1;
    }
}

二、NC161 二叉樹的中序遍歷數組

public int[] inorderTraversal (TreeNode root)函數

解法1:遞歸ui

public class Solution {
    // 中序遍歷的遞歸寫法 思路清晰可是不夠高效
    ArrayList<Integer> list = new ArrayList<>();
    public int[] inorderTraversal (TreeNode root) {
        recur(root);
        return list.stream().mapToInt(Integer::valueOf).toArray();
    }
    public void recur(TreeNode root) {
        if (root == null) return;
        recur(root.left);
        list.add(root.val);
        recur(root.right);
    }
}

解法2:非遞歸(往左找,出棧往右找)spa

public int[] inorderTraversal (TreeNode root) {
        ArrayList<Integer> arrList=new ArrayList<>();
        Stack<TreeNode> stack=new Stack<>();
        while(root!=null || !stack.isEmpty()){
            while(root!=null){
                stack.push(root);
                root=root.left;
            }
                root=stack.pop();
                arrList.add(root.val);
                root=root.right;
        }
        return arrList.stream().mapToInt(Integer::valueOf).toArray();
    }

三、NC72 二叉樹的鏡像3d

public TreeNode Mirror (TreeNode pRoot)code

public TreeNode Mirror (TreeNode pRoot) {
        if(pRoot == null) {
            return null;
        }
        if(pRoot.left == null && pRoot.right == null) {
            return pRoot;
        }
        TreeNode L = Mirror(pRoot.left);
        TreeNode R = Mirror(pRoot.right);
        pRoot.left = R;
        pRoot.right = L;
        return pRoot;
    }

四、NC13 二叉樹的最大深度blog

public int maxDepth (TreeNode root)遞歸

 

 解法1:非遞歸-層次遍歷+隊列

public int maxDepth (TreeNode root) {
        //經過層次遍歷計算二叉樹的深度
        if(root==null) return 0;
        Queue<TreeNode>queue=new LinkedList<>();
        queue.offer(root);
        int level=0,size;
        while(!queue.isEmpty()){
            size=queue.size();
            for(int i=0;i<size;i++){
                TreeNode node=queue.poll();
                if(node.left!=null) queue.offer(node.left);
                if(node.right!=null) queue.offer(node.right);
            }
            level++;
        }
        return level;
    }

解法2:遞歸

import java.util.*; 
/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */
public class Solution {
    /**
     * 
     * @param root TreeNode類 
     * @return int整型
     */
    public int maxDepth (TreeNode root) {
        if(root==null){
            return 0;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
         
        return 1 + Math.max(left,right);
    }
}

五、NC136 輸出二叉樹的右視圖

public int[] solve (int[] xianxu, int[] zhongxu)

 

 構造出二叉樹以後再用隊列找到每層的最後一個節點

HashMap<Integer,Integer> inOrderHashMap = new HashMap<>();
    public int[] solve (int[] xianxu, int[] zhongxu) {
        // write code here
        if (xianxu==null||zhongxu==null||xianxu.length==0||zhongxu.length==0) return new int[0];
        for (int i = 0; i < zhongxu.length; i++) {
            inOrderHashMap.put(zhongxu[i],i);
        }
        TreeNode root = buildTree(xianxu, 0, xianxu.length - 1, inOrderHashMap, 0, zhongxu.length - 1);
        Deque<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);
        int[] res = new int[xianxu.length];
        int count =0;
        while (!queue.isEmpty()){
            //拿到當前層元素個數
            int len = queue.size();
            System.out.println(len);
            for (int i = 0; i < len; i++) {
                TreeNode node = queue.poll();
                if (node.left!=null) queue.offer(node.left);
                if (node.right!=null) queue.offer(node.right);
                //到最後一個元素了
                if (i==len-1) res[count++] = node.val;
            }
        }
        //count是有效數組元素 0下標開始 跟左閉右開恰好對衝
        return Arrays.copyOfRange(res,0,count);
    }
    //inOrder: [inLeft,rootIndex-1] rootIndex [rootIndex+1,inRight]
    //preOrder: preLeft [preLeft+1,preLeft+rootIndex-inLeft] [preLeft+rootIndex-inLeft+1,preRight]
    private TreeNode buildTree(int[] xianxu, int preLeft, int preRight, HashMap<Integer, Integer> inOrderHashMap, int inLeft, int inRight) {
        //preLeft == preRight時 也要執行的 --葉子節點罷了
        if (preLeft>preRight||inLeft>inRight) return null;
        int rootIndex = inOrderHashMap.get(xianxu[preLeft]);
        TreeNode root = new TreeNode(xianxu[preLeft]);
        root.left = buildTree(xianxu, preLeft + 1, preLeft + rootIndex - inLeft, inOrderHashMap, inLeft, rootIndex - 1);
        root.right = buildTree(xianxu,preLeft+rootIndex-inLeft+1,preRight,inOrderHashMap,rootIndex+1,inRight);
        return root;
    }

六、NC102 在二叉樹中找到兩個節點的最近公共祖先

public int lowestCommonAncestor (TreeNode root, int o1, int o2)

 

  public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
        // write code here
        if(root.val == o1 || root.val == o2){
            return root.val;
        }
        TreeNode treeNode = order(root, o1, o2);
        return treeNode.val;
    }
    public TreeNode order(TreeNode root, int o1, int o2){
        if(root == null)
            return null;
        if(root.val == o1 || root.val == o2)
            return root;
        TreeNode left = order(root.left, o1, o2);
        TreeNode right = order(root.right, o1, o2);
         
        if(left != null && right != null)
            return root;
        if(left == null && right == null)
            return null;
         
        return left == null? right: left;
    }

七、NC15 求二叉樹的層序遍歷

public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root)

方法:隊列

import java.util.*;
 
/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */
 
public class Solution {
    /**
     * 
     * @param root TreeNode類 
     * @return int整型ArrayList<ArrayList<>>
     */
    public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
        // write code here
        if (root == null) {
            return new ArrayList<>();
        }
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        ArrayList<Integer> temp = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        Queue<TreeNode> mid = new LinkedList<>();
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            temp.add(node.val);
            if (node.left != null) {
                mid.add(node.left);
            }
            if (node.right != null) {
                mid.add(node.right);
            }
            if (queue.isEmpty()) {
                queue = mid;
                mid = new LinkedList<>();
                res.add(temp);
                temp = new ArrayList<>();
            }
        }
        return res;
    }
}

八、NC45 實現二叉樹先序、中序、後序遍歷

public int[][] threeOrders (TreeNode root)

 

 

 解法1:遞歸

import java.util.*;
 
/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */
 
public class Solution {
    /**
     * 
     * @param root TreeNode類 the root of binary tree
     * @return int整型二維數組
     */
    public int[][] threeOrders (TreeNode root) {
        if(root==null){
            return new int[0][0];
        }
        int[][] res = new int[3][];
        //先序
        List<Integer> list1 = new ArrayList<Integer>();
        first(root,list1);
        res[0] = list1.stream().mapToInt(Integer::intValue).toArray();
                
        //中序
        List<Integer> list2 = new ArrayList<Integer>();
        second(root,list2);
        res[1] = list2.stream().mapToInt(Integer::intValue).toArray();
         
        //後序
        List<Integer> list3 = new ArrayList<Integer>();
        third(root,list3);
        res[2] = list3.stream().mapToInt(Integer::intValue).toArray();
         
        return res;
    }
     
    private void first(TreeNode root,List<Integer> list){
        if(root==null){
            return;
        }
        list.add(root.val);
        first(root.left,list);
        first(root.right,list);
    }
     
    private void second(TreeNode root,List<Integer> list){
        if(root==null){
            return;
        }
        second(root.left,list);
        list.add(root.val);
        second(root.right,list);
    }
     
    private void third(TreeNode root,List<Integer> list){
        if(root==null){
            return;
        }
        third(root.left,list);
        third(root.right,list);
        list.add(root.val);
    }
     

方法2:非遞歸

    /**
     * 使用非遞歸的方法解決
     * @param root
     * @return
     */
    public int[][] threeOrders (TreeNode root) {
        if(root==null){
            return new int[0][0];
        }
        List<Integer> list1=new ArrayList<>();
        List<Integer> list2=new ArrayList<>();
        List<Integer> list3=new ArrayList<>();
        preOrder(list1,root);
        midOrder(list2,root);
        afterOrder(list3,root);
        int len = list1.size();
        int[][] res=new int[3][len];
        for (int i = 0; i < len; i++) {
            res[0][i]=list1.get(i);
        }
        for (int i = 0; i < len; i++) {
            res[1][i]=list2.get(i);
        }
        for (int i = 0; i < len; i++) {
            res[2][i]=list3.get(i);
        }
        return res;
    }
 
    /**
     * 先序遍歷
     * @param list1
     * @param root
     */
    private void preOrder(List<Integer> list1, TreeNode root) {
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();
            list1.add(node.val);
            if(node.right!=null){
                stack.push(node.right);
            }
            if(node.left!=null){
                stack.push(node.left);
            }
        }
    }
    /**
     * 中序遍歷
     * @param list2
     * @param root
     */
    private void midOrder(List<Integer> list2, TreeNode root) {
        Stack<TreeNode> stack=new Stack<>();
        while (!stack.isEmpty() || root!=null){
            while (root!=null){
                stack.push(root);
                root=root.left;
            }
            TreeNode node = stack.pop();
            list2.add(node.val);
            if(node.right!=null){
                root=node.right;
            }
        }
    }
    /**
     * 後序遍歷
     * @param list3
     * @param root
     */
    private void afterOrder(List<Integer> list3, TreeNode root) {
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();
            list3.add(node.val);
            if(node.left!=null){
                stack.push(node.left);
            }
            if(node.right!=null){
                stack.push(node.right);
            }
        }
        Collections.reverse(list3);
    }

九、判斷二叉樹是否對稱

public boolean isSymmetric (TreeNode root)

 

 

 方法1:遞歸

public class Solution {
    public boolean isSymmetric (TreeNode root) {
        if (root == null) return true;
        return recur(root.left, root.right);
    }
    // 遞歸輔助函數
    public boolean recur(TreeNode left, TreeNode right) {
        if (left == null && right == null) return true;
        else if (left != null && right == null) return false;
        else if (left == null && right != null) return false;
        else return left.val == right.val && recur(left.left, right.right) && recur(left.right, right.left);
    }
}

方法2:層次遍歷-Deque

public boolean isSymmetric (TreeNode root) {
    if (root == null) return true;
    Deque<TreeNode> queue = new LinkedList<>();
    queue.addLast(root.left);
    queue.addLast(root.right);
    while (!queue.isEmpty()) {
        TreeNode left = queue.pollLast();
        TreeNode right = queue.pollLast();
        if (left == null && right == null) continue;
        if (left == null || right == null) return false;
        if (left.val != right.val) return false;
     //隊列須要添加4個元素 queue.addFirst(left.left); queue.addFirst(right.right); queue.addFirst(left.right); queue.addFirst(right.left); }
return true; }

十、NC62 平衡二叉樹

public boolean IsBalanced_Solution(TreeNode root)

 

 

 

public class Solution {
    private boolean flag;
     
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root == null) {
            return true;
        }
        flag = true;
        getDepth(root);
        return flag;
    }
     
    public int getDepth(TreeNode root) {
        if(root == null) {
            return 0;
        }
        int L = getDepth(root.left);
        int R = getDepth(root.right);
        if(Math.abs(L - R) > 1) {
            flag = false;
            return -1;
        }
        return Math.max(L, R) + 1;
    }
}

//平衡二叉樹要求:左右子樹的深度差不超過1,而且左右子樹也是平衡二叉樹(空樹也能夠理解成平衡二叉樹)
public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root==null) return true;
        return (Math.abs(depth(root.left)-depth(root.right))<=1)
            && IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
    }
    public int depth(TreeNode root){
        if(root==null) return 0;
        return Math.max(depth(root.left),depth(root.right))+1;
    }
}

import java.util.*;
public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
         
        if(root == null){
            return true;
        }
         
        //判斷兩個子樹的高度差絕對值是否超過1
        if(Math.abs(getTreeDeep(root.left) - getTreeDeep(root.right)) > 1){
            return false;
        }
         
        return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
    }
     
    //計算二叉樹的深度
    public int getTreeDeep(TreeNode root){
        if(root == null){
            return 0;
        }
         
        int leftNum = 1;
        int rightNum = 1;
         
        if(root.left != null){
            leftNum += getTreeDeep(root.left);
        }
        if(root.right != null){
            rightNum += getTreeDeep(root.right);
        }
         
        return leftNum >= rightNum ? leftNum : rightNum;
    }
}

總結:左右子樹也要知足&左右子樹深度之差不超過1

十一、NC9 二叉樹中是否存在節點和爲指定值的路徑---dfs/回溯

public boolean hasPathSum (TreeNode root, int sum)

 

 方法1:遞歸--結束條件,選擇列表,路徑作選擇

public class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if (root == null)
            return false;
 
        sum -= root.val;
        if (sum == 0 && root.left == null && root.right == null)
            return true;
 
        return hasPathSum(root.left, sum) || hasPathSum(root.right, sum);
    }
}

方法2:dfs

 public boolean hasPathSum (TreeNode root, int sum) {
        // write code here
        return dfs(root,sum);
    }
    private boolean dfs(TreeNode root, int sum) {
        if(root == null) return false;
        sum -= root.val;
        if(root.left == null && root.right == null && sum == 0) return true;
        return dfs(root.left,sum) || dfs(root.right,sum);
    }

十二、NC5 二叉樹根節點到葉子節點的全部路徑和---dfs

public int sumNumbers (TreeNode root) 

 

public class Solution {
    List<Integer> list;
    public int sumNumbers (TreeNode root) {
        // write code here
        list=new ArrayList();
        sumNumbersHelp(root,0);
        int count=0;
        for(Integer l:list){
            count+=l;
        }
        return count;
    }
    public void sumNumbersHelp (TreeNode root,int num) {
        if (root != null) {
            num=num*10+root.val;
            if (root.left == null && root.right == null) {  // 當前節點是葉子節點
                list.add(num);  // 把路徑加入到答案中
            } else {    // 當前節點不是葉子節點,繼續遞歸遍歷
                sumNumbersHelp(root.left, num);
                sumNumbersHelp(root.right, num);
            }
        }
    }
}
相關文章
相關標籤/搜索