LeetCode 297, 932

253 阅读2分钟

LeetCode 297 Serialize and Deserialize Binary Tree

链接:leetcode.com/problems/se…

方法1:DFS

时间复杂度:O(n)

空间复杂度:O(n)

想法:按照二叉树的前序遍历写出它的序列化表达式。直接递归写,如果遇到null的话就写一个#号进去。如果是以这种方式构建,那么在反序列化的之后,用一个index记录在原字符串分割出来的数组当中的下标,index一直往上加即可。因为是前序遍历,数组当中一定是这样的分布:根节点|左子树|右子树。因此当前index遍历到的地方如果不是null,那就是当前子树的根节点,然后创建它,继续递归调用即可。这道题不让我们用任何全局的变量,这也有道理,因为不然的话你直接开个全局变量把原来的树存进去就完了,那还做个啥。所以为了使index一直递增,并且改变之后影响所有对它的调用,因此我们采用一个只有一个元素的数组。

代码:

public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        preOrder(root, sb);
        return sb.toString();
    }
    
    private void preOrder(TreeNode root, StringBuilder sb) {
        if (root == null) {
            sb.append("#,");
            return;
        }
        
        sb.append(root.val);
        sb.append(',');
        preOrder(root.left, sb);
        preOrder(root.right, sb);
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        int[] index = new int[1];
        return build(data.split(","), index);
    }
    
    private TreeNode build(String[] data, int[] index) {
        if (data.length == index[0]) {
            return null;
        }
        
        String val = data[index[0]++];
        if (val.equals("#")) {
            return null;
        }
        TreeNode root = new TreeNode(Integer.parseInt(val));
        root.left = build(data, index);
        root.right = build(data, index);
        return root;
    }
}

方法2:BFS

时间复杂度:O(n)

空间复杂度:O(n)

想法:这个是来自九章的做法。但我其实觉得这道题用BFS来做的话比DFS稍微更绕一点,因为要判定一个节点是左节点还是右节点。这种BFS基本上就是LeetCode的样例里面写一个树的格式,我们看到这道题的样例1写的是root = [1,2,3,null,null,4,5],整个数组的构成是:根节点|左子节点|右子节点|左子节点的左节点|左子节点的右节点|右子节点的左节点|右子节点的右节点|...... 有点类似BFS,但是在序列化的时候不会往外弹元素,因此用一个List就行了。

在反序列化的时候,用index记录当前在构建的子树的根节点,然后for循环从前往后,因为严格是按照左子节点、右子节点的顺序来的,因此用一个boolean值记录i指向的是index指向的节点的左子节点还是右子节点。

代码:

public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root == null) return "{}";
        
        List<TreeNode> queue = new ArrayList<>();
        queue.add(root);
        for(int i = 0; i < queue.size(); i++){
            TreeNode node = queue.get(i);
            if(node == null) continue;
            queue.add(node.left);
            queue.add(node.right);
        }
        
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        sb.append(queue.get(0).val);
        for(int i = 1; i < queue.size(); i++){
            if(queue.get(i) == null){
                sb.append(",#");
            }
            else{
                sb.append(",");
                sb.append(queue.get(i).val);
            }
        }
        sb.append("}");
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data.equals("{}")){
            return null;
        }
        
        String[] vals = data.substring(1, data.length()-1).split(",");
        List<TreeNode> queue = new ArrayList<>();
        int index = 0;
        boolean isLeftChild = true;
        TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
        queue.add(root);
        
        for(int i = 1; i < vals.length; i++){
            if(!vals[i].equals("#")){
                TreeNode node = new TreeNode(Integer.parseInt(vals[i]));
                if(isLeftChild){
                    queue.get(index).left = node;
                }
                else{
                    queue.get(index).right = node;
                }
                queue.add(node);
            }
            if(!isLeftChild){
                index++;
            }
            isLeftChild = !isLeftChild;
        }
        
        return root;
        
    }
}

LeetCode 932 Beautiful Array

链接:leetcode.com/problems/be…

方法:观察构建

时间复杂度:O(n)

空间复杂度:O(n)

想法:学习lee哥的解法leetcode.com/problems/be… 。当时做这道题确实也想到按奇偶分了,如果左边半个数组全是奇数,右边半个全是偶数,那么从左边选一个,从右边选一个,和是奇数,永远不会是某个数的两倍。但当时没想清楚左右两边分别怎么构造。构造方法是,左右两边也分别为beautiful array,并且是从上一步的beautiful array直接算出来的。如果在某一步,数组是A,长度是N,那么,构造A1 = A * 2 - 1, A2 = A * 2 B = A1 + A2,算出B来之后,用A指向它,进行下一步迭代。

代码:

class Solution {
    public int[] beautifulArray(int n) {
        List<Integer> res = new ArrayList<>();
        res.add(1);
        
        while (res.size() < n) {
            List<Integer> t = new ArrayList<>();
            for (Integer num : res) {
                if (num * 2 - 1 <= n) {
                    t.add(num * 2 - 1);
                }
            }
            for (Integer num : res) {
                if (num * 2 <= n) {
                    t.add(num * 2);
                }
            }
            res = t;
        }
        
        int[] ans = new int[n];
        for (int i = 0; i < n; i++) {
            ans[i] = res.get(i);
        }
        
        return ans;
    }
}