LeetCode 297 Serialize and Deserialize Binary Tree
方法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
方法:观察构建
时间复杂度: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;
}
}