LeetCode解题报告—— Unique Binary Search Trees & Binary Tree Level Order Traversal & Binary Tree Zigzag Level Order Traversal

1. Unique Binary Search Trees

Given n, how many structurally unique BST's (binary search trees) that store values 1...n?

For example,
Given n = 3, there are a total of 5 unique BST's.

   1         3     3      2      1
           /     /      /       
     3     2     1      1   3      2
    /     /                        
   2     1         2                 3

思路:和 Unique Binary Search Trees II 不同,只是需要计算总共的数量,可以利用dp来解决。从1~n选择i作为root,那么1到i-1构成其左子树,i+1到n构成其右子树。作如下定义,

G(n): the number of unique BST for a sequence of length n.

F(i, n), 1 <= i <= n: the number of unique BST, where the number i is the root of BST, and the sequence ranges from 1 to n.

从以上定义,可得

G(n) = F(1, n) + F(2, n) + ... + F(n, n). 

并且G(0)=1, G(1)=1. 即空树和只有一个节点的情况。对于dp,要解决的问题是能分成若干个相同的子问题,并且计算有重复的情形。以 [1, 2, 3, 4, 5, 6, 7] 为例子,要计算的是G(7),如果以3为根,要计算F(3,7)。[1,2]构成左子树,[4,5,6,7]构成右子树。对于[1,2],其实就是计算G(2),而对于[4,5,6,7],可以将其等同于计算G(4),即F(3,7) = G(2) * G(4)。因此有下面等式

F(i, n) = G(i-1) * G(n-i)	1 <= i <= n 

结合上面的公式可得出

G(n) = G(0) * G(n-1) + G(1) * G(n-2) + … + G(n-1) * G(0) 

所以从低向上计算,即从G(0),G(1)开始一直计算出G(n)即可。

public int numTrees(int n) {
    int [] G = new int[n+1];
    G[0] = G[1] = 1;
    
    for(int i=2; i<=n; ++i) {
        for(int j=1; j<=i; ++j) {
            G[i] += G[j-1] * G[i-j];
        }
    }

    return G[n];
}

 

2. Binary Tree Level Order Traversal

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

For example:
Given binary tree [3,9,20,null,null,15,7],

    3
   / 
  9  20
    /  
   15   7

return its level order traversal as:

[
  [3],
  [9,20],
  [15,7]
]

思路:层次遍历二叉树,没什么好说的,主要是掌握队列的用法。

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        List<List<Integer>> wrapList = new LinkedList<List<Integer>>();
        
        if(root == null) return wrapList;
        
        queue.offer(root);
        while(!queue.isEmpty()){
            int levelNum = queue.size();
            List<Integer> subList = new LinkedList<Integer>();
            for(int i=0; i<levelNum; i++) {
                if(queue.peek().left != null) queue.offer(queue.peek().left);
                if(queue.peek().right != null) queue.offer(queue.peek().right);
                subList.add(queue.poll().val);
            }
            wrapList.add(subList);
        }
        return wrapList;
    }
}

关于java中队列的用法可以参考这篇博文:https://www.cnblogs.com/samjustin/p/5785078.html

3. Binary Tree Zigzag Level Order Traversal

Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).

For example:
Given binary tree [3,9,20,null,null,15,7],

    3
   / 
  9  20
    /  
   15   7

return its zigzag level order traversal as:

[
  [3],
  [20,9],
  [15,7]
]

思路:基于上个题目的改进,本来以为改下上题的代码,判断每层层号的奇偶,再逆置,这样做的确可以解题,但是太过繁琐。还是参考了下答案。使用递归思路求解,对于层次遍历来说,每一层的遍历,都是逻辑相同,参数不同。关键是怎么在这个递归中寻找终止条件,以及一层层向下递归时固定的参数变化规律。

public class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) 
    {
        List<List<Integer>> sol = new ArrayList<>();
        travel(root, sol, 0);
        return sol;
    }
    
    private void travel(TreeNode curr, List<List<Integer>> sol, int level)
    {
        if(curr == null) return; // 没有下层了,递归就往上层返回
        
        if(sol.size() <= level) // 当递归发现还有下层的话,就为这层新建个List,并加入到sol中
        {
            List<Integer> newLevel = new LinkedList<>();
            sol.add(newLevel);
        }
        
        List<Integer> collection  = sol.get(level);  // 这里根据层号取List,所以即使两个从上到下的递归路径不同,但是相同层取到的还是相同的List
        if(level % 2 == 0) collection.add(curr.val);  // 根据层号奇偶判断这层的List在加入元素时是正序还是逆序
        else collection.add(0, curr.val);  // 学到了
        
        travel(curr.left, sol, level + 1);   // 往下层左子树递归
        travel(curr.right, sol, level + 1);  // 往下层右子树递归
    }
}

上面的基本递归思路是利用到DFS,整个过程每层的元素不是一层层遍历完的,而是每递归到一个底层,从这层往上的所有层所对应的List都添加了在这层遍历到的元素,并且根据层号的奇偶决定是往后插还是往前插,这样来实现顺序和倒序的遍历,这也为层次遍历提供了一种递归实现的思路。注意上面的 collection.add(0, curr.val) 方法,将值插入指定位置,原来位置上的值会依次往后移。

原文地址:https://www.cnblogs.com/f91og/p/8684066.html