ARTS Week 22

Algorithm

本周的 LeetCode 题目为 297. 二叉树的序列化与反序列化

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

  1
 / \
2   3
   / \
  4   5
输入:root = [1,2,3,null,null,4,5]
输出:[1,2,3,null,null,4,5]

二叉树的序列化后的结果采用先序遍历的方式。

  • 在进行序列化时,先判断当前节点是否为空,若为空则记录 null,若不为空,则先将根的值和分隔符(',')添加,再依次递归处理当前节点的左子树、右子树。
  • 在进行反序列化时,先判断当前是否为 null,若为 null 则返回 null,若不为 null,则先以当前值构造出根节点,移除第一个元素,再依次构建该节点的左子树、右子树。
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        realSerialize(root, sb);
        return sb.toString();
    }

    public void realSerialize(TreeNode root, StringBuilder sb) {
        if (root != null) {
            sb.append(root.val);
            sb.append(",");
            realSerialize(root.left, sb);
            realSerialize(root.right, sb);
        } else {
            sb.append("null,");
        }
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        String[] dataArr = data.split(",");
        List<String> dataList = new ArrayList<>(Arrays.asList(dataArr));
        // dataList = Arrays.asList(dataArr);
        TreeNode ans = realDeserialize(dataList);
        return ans;
    }

    public TreeNode realDeserialize(List<String> dataList) {
        if (dataList.get(0).equals("null")) {
            dataList.remove(0);
            return null;
        }

        TreeNode root = new TreeNode(Integer.valueOf(dataList.get(0)));
        dataList.remove(0);
        root.left = realDeserialize(dataList);
        root.right = realDeserialize(dataList);
        return root;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

Review

本周 Review 的英文文章为:如何在 git 中使用 squashrebase

作者详细介绍了使用 squashrebase 的流程,首先你需要备份一个分支用来尝试:

git checkout my-branch-name
git branch backup-my-branch-name
git push origin backup-my-branch-name

而后查看日志找到不属于你的最新提交的 id,别忘了复制它

git log

而后开始 rebase 操作,将 -i 后面的内容替换为你刚刚找到的提交 id

git rebase -i the-commit-id-you-looked-up-goes-here

通过在除第一个提交之外的所有提交前面放置“s”而不是“pick”来标记要压缩(squash)的提交。而后保存并关闭,等待弹出新的文本编辑器提示来输入你的 commit 信息。

使用 git status 来检查是否有任何问题。

接下来作者将所有提交都合并到 main 分支中,先确保本地的 main 分支是最新的

git checkout main
git pull origin main

接下来进行 rebase 操作,先切换分支再 rebase

git checkout my-branch-name
git rebase main

修复发生的 git 冲突后,暂存如下的文件:

git add some-file.js

而后再继续完成 rebase

git rebase --continue

最后提交 commit,请先检查分支是你的分支!

git push --force-with-lease origin my-branch-name

如果途中出现了问题,你还有一个备份分支可以用来恢复,或者使用 git rebase --abort 来中止正在进行的 rebase

为什么要在 rebase 前进行 squash?在使用 squash 压缩提交后,rebase 需要解决的冲突至多需要一次,而当你的公司/组织/项目要求你不得压缩时,那么就不要使用 squash

Tip

使用宏定义的注意事项,宏定义是直接替换,并不是保存计算的结果。示例代码如下:

#include <stdio.h>

#define NUM_0 4
#define NUM_1 5-1
#define NUM_2 (5-1)

int main()
{
    printf("%d\n", 5 % NUM_0); // 5 % NUM_1 = 5 % 4 = 1
    printf("%d\n", 5 % NUM_1); // 5 % NUM_1 = 5 % 5-1 = 0 - 1 = -1
    printf("%d\n", 5 % NUM_2); // 5 % NUM_1 = 5 % (5-1) = 5 % 4 = 1
    return 0;
}

程序的运行结果如下:

$ clang test.c                     
$ ./a.out     
1
-1
1

Share

未来几周内打算抽空认真地、系统性地回顾下基本的数据结构、算法,为下一步做 LeetCode 题目做准备。

posted @ 2022-01-23 19:29  永远是萌新的阿岩  阅读(45)  评论(0编辑  收藏  举报