LeetCode中的數據結構2:二叉樹

二叉樹具有天然的遞歸性,二叉樹問題也常用遞歸方式求解。遞歸函數應該包含兩部分:遞歸終止條件和遞歸過程。
LeetCode 104 Maximum Depth of Binary Tree,求二叉樹的最大深度,就是使用遞歸方法求解的非常簡單的二叉樹問題。

public int maxDepth(TreeNode root) {
	// 遞歸終止條件
    if (root == null) {
        return 0;
    }
    // 遞歸過程
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}

LeetCode 226 Invert Binary Tree是知名血案問題,因爲Max Howell(Homebrew的作者)因爲沒有解出這道題被Google拒絕。

public TreeNode invertTree(TreeNode root) {
    if(root == null) {
        return null;
    }
    TreeNode newRight = invertTree(root.left);
    TreeNode newLeft = invertTree(root.right);
    root.left = newLeft;
    root.right = newRight;
    return root;
}

還有很多類似的問題,例如LeetCode 100、101
100 Same Tree
Given two binary trees, write a function to check if they are the same or not. Two binary trees are considered the same if they are structurally identical and the nodes have the same value.

public boolean isSameTree(TreeNode p, TreeNode q) {
    if (p==null && q==null) {
        return true;
    }
    if (p==null || q==null) {
        return false;
    }
    Queue<TreeNode> queue1 = new LinkedList<TreeNode>();
    queue1.offer(p);
    Queue<TreeNode> queue2 = new LinkedList<TreeNode>();
    queue2.offer(q);
    while (!queue1.isEmpty() && !queue2.isEmpty()) {
        TreeNode node1 = queue1.poll();
        TreeNode node2 = queue2.poll();
        if (node1.val != node2.val) {
            return false;
        }
        if (node1.left != null && node2.left != null) {
            queue1.offer(node1.left);
            queue2.offer(node2.left);
        } else if (node1.left != null || node2.left != null) {
            return false;
        }
        if (node1.right != null && node2.right != null) {
            queue1.offer(node1.right);
            queue2.offer(node2.right);
        } else if (node1.right != null || node2.right != null) {
            return false;
        }        
    }
    if (!queue1.isEmpty() || !queue2.isEmpty()) {
        return false;
    }
    return true;
}

101 Symmetric Tree

public boolean isSymmetric(TreeNode root) {
    if(root == null) {
        return true;
    }
    return isMirror(root.left, root.right);
}
private boolean isMirror(TreeNode node1, TreeNode node2) {
    if (node1 == null && node2 == null) {
        return true;
    }
    if (node1 == null || node2 == null) {
        return false;
    }
    return node1.val == node2. val 
        && isMirror(node1.left, node2.right)
        && isMirror(node1.right, node2.left);
}

LeetCode 222 Count Complete Tree Nodes,Given a complete binary tree, count the number of nodes.給定一棵完全二叉樹,求完全二叉樹的節點個數。其中完全二叉樹是指:除了最後一層,所有層的節點數達到最大,與此同時,最後一層的所有節點都在最左邊。但是我的解法並沒有用到完全二叉樹的性質,而是前序遍歷整棵二叉樹,數了節點個數,所以這道題有更好的解法待探究。

class Solution {
    int count = 0;
    public int countNodes(TreeNode root) {
        preOrder(root);
        return count;
    }
    public void preOrder(TreeNode root) {
        if (root ==null) {
            return;
        }
        count++;
        preOrder(root.left);
        preOrder(root.right);
    }
}

LeetCode 110 Balanced Binary Tree,Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary tree is defined as: a binary tree in which the depth of the two subtrees of every node never differ by more than 1.判斷一棵二叉樹是否爲平衡二叉樹。平衡二叉樹的定義是,每一個幾點的左右子樹的高度差不能超過1。

public boolean isBalanced(TreeNode root) {
    if (root == null) {
        return true;
    }
    if (Math.abs(longPath(root.left)-longPath(root.right))>1) {
        return false;
    }
    return isBalanced(root.left) && isBalanced(root.right);       
}
private int longPath(TreeNode root) {
    if (root==null) {
        return 0;
    }
    return Math.max(longPath(root.left), longPath(root.right))+1;
}

完成正確的遞歸函數的關鍵之一就是找到遞歸終止條件。上面幾道題目的遞歸終止條件都很簡單,看下一下幾道題目。
LeetCode 112 Path Sum,Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
Note: A leaf is a node with no children. 給出一棵二叉樹以及一個數字sum,判斷在這棵二叉樹上是否存在一條從根到葉子的路徑,其路徑上的所有節點和爲sum。注意是從根到葉子節點。

public boolean hasPathSum(TreeNode root, int sum) {
    if (root == null) {
        return false;
    }
    if (isLeaf(root)) {
        return sum==root.val;
    }
    return hasPathSum(root.left, sum-root.val) || hasPathSum(root.right, sum-root.val);
}    
private boolean isLeaf(TreeNode node) {
    if (node == null) {
        return false;
    } 
    return node.left == null && node.right == null;
}

LeetCode 111 Minimum Depth of Binary Tree, Given a binary tree, find its minimum depth. 求一棵二叉樹的最低深度

public int minDepth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    if (!isLeaf(root) && root.left == null) {
        return minDepth(root.right)+1;
    }
    if (!isLeaf(root) && root.right == null) {
        return minDepth(root.left)+1;
    }
    return Math.min(minDepth(root.left), minDepth(root.right))+1;
}

private boolean isLeaf(TreeNode node) {
    if (node == null) {
        return false;
    } 
    return node.left==null && node.right==null;
}

LeetCode 404 Sum of Left Leaves, Find the sum of all left leaves in a given binary tree. 求一個二叉樹所有左葉子的和。

class Solution {
    int sum = 0;
    public int sumOfLeftLeaves(TreeNode root) {
        if (root == null) {
            return sum;
        }
        if (isLeaf(root.left)) {
            sum += root.left.val;
        }
        sumOfLeftLeaves(root.left);
        sumOfLeftLeaves(root.right);
        return sum;
    }
    
    private boolean isLeaf(TreeNode node) {
        if (node == null) {
            return false;
        } 
        return node.left == null && node.right==null;
    }
}

在看幾道遞歸邏輯複雜一些的。
LeetCode 257 Binary Tree Paths, Given a binary tree, return all root-to-leaf paths. 給定一棵二叉樹,返回所有變是從根節點到葉子節點路徑的字符串。

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> binaryTreePaths(TreeNode root) {
        if (root == null) {
            return res;
        }
        String s = "";
        findPath(s, root);
        return res;       
    }
    private void findPath(String s, TreeNode root) {
        s += (root.val + "->");
        if (root.left == null && root.right==null) {
            s=s.substring(0, s.length()-2);
            res.add(s);
            return;
        }
        if (root.left != null) {
            String s1 = new String(s);
            findPath(s1, root.left);
        }
        if (root.right != null) {
            String s2 = new String(s);
            findPath(s2, root.right);
        }       
    }
}

LeetCode 113 Path Sum II, Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum. 給定一棵二叉樹,返回所有從根節點到葉子節點的和爲sum的路徑。

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        if (root == null) {
            return res;
        }
        List<Integer> list = new ArrayList<>();
        pathSum(list, root, sum);
        return res;
    }
    private void pathSum(List<Integer> list, TreeNode root, int sum) {
        list.add(root.val);
        if (root.left == null && root.right==null && sum==root.val) {
            List<Integer> list1 = copyArrayList(list);
            res.add(list1);
            return;
        }
        if (root.left != null) {
            List<Integer> list1 = copyArrayList(list);
            pathSum(list1, root.left, sum-root.val);
        }
        if (root.right != null) {
            List<Integer> list1 = copyArrayList(list);
            pathSum(list1, root.right, sum-root.val);
        }
    }
    
    private ArrayList<Integer> copyArrayList(List<Integer> list) {
        ArrayList<Integer> copy = new ArrayList<>(Arrays.asList(new Integer[list.size()]));
        for (int i=0; i<list.size(); i++) {
            copy.set(i, list.get(i));
        }
        return copy;
    }
}

LeetCode 129 Sum Root to Leaf Numbers, Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. An example is the root-to-leaf path 1->2->3 which represents the number 123. Find the total sum of all root-to-leaf numbers. 給定一棵二叉樹,每個節點只包含數字0-9,從根節點到葉子節點的每條路徑可以表示成一個數,請這些數的和。例如從根節點到葉子節點分別爲1->2->3,那麼這條路徑代表數字123。求所有路徑代表的數字的和。

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public int sumNumbers(TreeNode root) {
        if (root == null) {
            return 0;
        }
        List<Integer> list = new ArrayList<>();
        findPath(root, list);
        Integer ans = 0;
        for (int i=0; i<res.size(); i++) {
            List<Integer> listTemp = res.get(i);
            Integer ansTemp = 0;
            for (int j=0; j<listTemp.size(); j++) {
                ansTemp += listTemp.get(j)*(int)(Math.pow(10, (listTemp.size()-j-1)));
            }
            ans += ansTemp;
        }
        return ans;
    }
    private void findPath(TreeNode root, List<Integer> list) {
        list.add(root.val);
        if (root.left == null && root.right == null) {
            List<Integer> copy = copyArrayList(list);
            res.add(copy);
            return;
        }
        if (root.left != null) {
            List<Integer> copy = copyArrayList(list);
            findPath(root.left, copy);
        } 
        if (root.right != null) {
            List<Integer> copy = copyArrayList(list);
            findPath(root.right, copy);
        }
    }
    private List<Integer> copyArrayList(List<Integer> list) {
        List<Integer> copy = new ArrayList<>(Arrays.asList(new Integer[list.size()]));
        for (int i=0; i<list.size(); i++) {
            copy.set(i, list.get(i));
        }
        return copy;
    }
}

上面都是普通二叉樹涉及的算法,二叉樹中有一類非常特殊的二叉樹:二分搜索樹。對於一棵二分搜索樹,每個節點的鍵值大於左孩子,每個節點的鍵值小於右孩子,以左右孩子爲根的子樹仍未二分搜索樹。
LeetCode 235 Lowest Common Ancestor of a Binary Search Tree, Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST. 給定一棵二分搜索樹和兩個節點,尋找這兩個節點的最近公共祖先。

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if (root == null || p == null || q == null) {
        return null;
    }
    if (root.val>p.val && root.val>q.val) {
        return lowestCommonAncestor(root.left, p, q);
    }
    if (root.val<p.val && root.val<q.val) {
        return lowestCommonAncestor(root.right, p, q);
    }
    return root;
}

還有236題,在普通二叉樹中尋找兩個節點的最近公共祖先。
二分搜索樹的經典題目還有:98、450、108、230,會陸續完善。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章