一、Algorithms
本周做的还是 DFS 相关的问题,题目要求是比较两棵二叉树是否相同,即每个节点相同并且 val 相等
思路
开始的思路是使用深度遍历访问到两棵树的每个节点并比较 val 是否相同,如果一直到遍历结束都相同那么说明是同一棵树。但这样的问题是每次都需要遍历所有节点,正确的做法应该是一旦发现不同立即返回即可。
先假设两个树是相同的。然后同时开始对两棵树进行 DFS,一旦有一个节点其类型不一致或者 val 不一致,就表示两棵树不相同,此时终止遍历返回即可。这样好处时当两棵树不一致时可以将遍历次数降到最低,在两棵树相同时遍历次数最多,运行时间最长。
实现代码如下, 运行时间 3ms, beats 99.91%。
class Solution {
private boolean isSame = true;
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
} else if (p instanceof TreeNode && q instanceof TreeNode) {
if (p.val != q.val) {
return false;
}
} else {
return false;
}
dfs(p, q);
return isSame;
}
public void dfs(TreeNode p, TreeNode q) {
if (p == null && q == null){
return;
}
if ((p instanceof TreeNode) && (q instanceof TreeNode)) {
if (p.val != q.val) {
isSame = false;
return;
}
}else {
isSame = false;
return ;
}
dfs(p.left, q.left);
dfs(p.right, q.right);
}
}
二. Review
最近公司在上 ES,因此本周读了耗子哥在专栏中推荐的一篇文章 9 tips on ElasticSearch configuration for high performance。
文中主要提到了几点优化建议:
- master 节点维护集群状态,包括索引 mapping、分配分片,追踪每个 Index 和 shard 的状态,这些数据的维护都需要消耗资源。因此如果允许 Index 无限制的增加,那么最终会导致集群状态数据过多导致 master 节点挂掉。
- 在线上部署时尽量使 client、data 和 master 节点分离。
- 设置bootstrap.memory_lock: true, 可提升读写效率
- 关闭批量删除功能,这是一个高危操作: action.destructive_requires_name true
- 当需要用到过滤和聚合分析功能时建议开启 field 的 doc_values 属性
- ES 通过 discovery.zen 来设置与其他节点通信的相关配置,主要有以下三个
# 集群中其他节点的 host,主要是 master-elgible node
discovery.zen.ping.unicast.hosts: ["esmaster01","esmaster02","esmaster03"]
# ES ping 节点的超时时间
discovery.zen.fd.ping_timeout: 30s
# 最小选举数
discovery.zen.minimum_master_nodes: 2
minimum_master_nodes 设置的是最小选举数。即当集群出现网络问题某一个 master 节点失效后,只有当集群的 master-eligible 节点大于等于 minimum_master_nodes 时 时才可以进行 master 节点的选举,这主要是为了避免脑裂问题.
也可以通过如下 api 进行设置。
PUT _cluster/settings
{
# transient 配置不是持久性的,集群重启后就失效
# persistent 可以进行持久化的修改
"transient": {
"discovery.zen.minimum_master_nodes": 2
}
}
另外还有三个 tip 其相关内容还没有完全搞明白,下周搞清楚与下周的 review 一起发。
三、Technique
分享一个 Linux 的命令行使用吧,我们经常使用 htop 查看系统运行情况,或者使用 ps 查看某个进程的运行,在使用 ps 时可以结合 sort 命令 对查询出的进程按照内存占用率和 CPU 占用率进行排序, 通过这个命令也可以快速的查看哪些程序占用了过多的资源:
# 按照 cpu 利用率排序
ps aux | sort -nk 3
# 按照内存使用率进行排序
ps aux | sort -nk 4
这里也顺便分享一个查询 Linxu 命令用法的网站 linux-command, 对于 man 命令读英文不太习惯的同学可以用这个网站快速查询用法。
四. share
本周读了耗子哥专栏编程范式系列中关于泛型的文章,对应的也读了 《冒号课堂》一书关于泛型的介绍,两份资料都表达的相似的观点:
- 泛型,本质上是使算法脱离于具体的数据结构,使其具有更加的通用性。
在实际的操作中,开始工作的时候用的是 Java,现在用 Python。个人体验上动态语言在编写程序时确实提高了程序的通用性,专注于要实现的逻辑即可,不必考虑各种数据类型。但随之而来的就是可读性的下降。当回头去看很久之前的一段代码时,除非命名的特别合理清晰,否则经常要花费一定的时去梳理逻辑,搞清楚某个变量的类型和意义是什么,尤其是自定义的对象类型。而 Java 虽然也有泛型,但是还是一门静态语言,个人感觉代码整体的可读性和可维护性都要比 Python 好,因为类型的存在可以很直观的知晓我们的程序是处理哪种数据的。泛型也算是一种 trade-off 吧,在牺牲可读性的基础上提高了通用性,使我们的代码更加符合 DRY 原则,同时不必因为类型而重复多份,也一定程度的提高了开发效率。