阅读本文大概需要 8 分钟。
每周完成一个 ARTS
Algorithm 来源剑指 offer 数组中只出现一次的数字
Review 分享 DNS 协议的简单理解。
Tip 分享如何编写可维护的 Go 语言代码。
Share 聊聊技术路线的选择。
PS:由于公众号不支持添加外链,所以大家遇到有链接的地方滑到文章最下面点击阅读原文就可以访问了哈,如果觉得文章不错,欢迎分享给周围的朋友们哈
1.Algorithm
剑指 offer 数组中只出现一次的数字 链接 难度:[Medium]]
【题意】
一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
Example input 3 4 5 5 6 6 output 3 4
【思路】
首先我们考虑这个问题的一个简单版本,也是 LeetCode 的一道题:一个数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。
这个题目的突破口在哪里?题目为什么要强调只有一个数字出现一次,其他的出现两次?我们想到了异或运算的性质:任何一个数字异或它自己都等于 0 。
也就是说,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字,因为那些出现两次的数字全部在异或中抵消掉了。
这个性质太赞了!
那么有了上面简单问题的解决方案之后,我们回到原始的问题。
1. 如果能够把原数组分为两个子数组。在每个子数组中,把这两个只出现一次的数字分配进去,而其它数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现一次的数字了。
2. 从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。因为其它数字都出现了两次,在异或中全部抵消掉了。
3. 由于这两个数字肯定不一样,那么这个异或结果肯定不为 0 ,也就是说在这个结果数字的二进制表示中至少就有一位为 1 。我们在结果数字中找到第一个为 1 的位的位置,记为第 N 位。现在我们以第 N 位是不是1 为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第 N 位都为1 ,而第二个子数组的每个数字的第 N 位都为 0 。
4. 现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其它数字都出现了两次, 这样继续对两个子数组相异或则可以分别求出两个只出现一次的数字。因此到此为止,问题解决。
【解法一】(Java)
/*
Author: https://github.com/rongweihe
Time: 2019-03-23
*/
// Time complexity : O(n).
// Space complexity : O(1).
// num1,num2分别为长度为1的数组。传出参数
// 将num1[0],num2[0]设置为返回结果
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if(array == null || array.length <= 1){
num1[0] = num2[0] = 0;
return;
}
int len = array.length, index = 0, sum = 0;
for(int i = 0; i < len; i++){
sum ^= array[i];
}
for(index = 0; index < 32; index++){
if((sum & (1 << index)) != 0) break;
}
for(int i = 0; i < len; i++){
if((array[i] & (1 << index))!=0){
num2[0] ^= array[i];
}else{
num1[0] ^= array[i];
}
}
}
}
2.Review
DNS 协议的简单理解
受到这篇文章的启发
http://www.networksolutions.com/support/what-is-a-domain-name-server-dns-and-how-does-it-work/
(1)来源:为什么要有 DNS 协议
互联网上的网站的数目非常多,如果全部用 IP 地址进行访问,恐怕很难记住。于是,就需要一个地址簿(就是 DNS 服务器)根据名称,可以查看具体的地址。
(2)层次结构:DNS 服务器
DNS服务器非常重要,要求设置为高可用,高并发和分布式的。
因此有以下的树状的层次结构
根 DNS 服务器:返回顶级域 DNS 服务器的 IP 地址。
顶级域 DNS 服务器:返回权威 DNS 服务器的 IP 地址。
权威 DNS 服务器:返回相应主机的 IP 地址。
(3)DNS 解析流程
为了提高 DNS 的解析性能,很多网络就会就近部署 DNS 缓存服务器。于是,就有了下面的 DNS 解析流程。
(4)DNS 的内部负载均衡和全局负载均衡
我的简单理解:我在北京,有一天想和同学去吃北京烤鸭了,但是北京这么大,肯定有好多家北京烤鸭的门店,所以,如果我想吃北京烤鸭了,DNS 告诉我,离你最近的有一家北京烤鸭,去那吃也不错,我就可以就近选择一家店,而不是大家都去吃同一家烤鸭店,这就是负载均衡。
内部负载均衡:不同的应用互相访问,如果有一个应用访问撑不住了,怎么办?内部部署多个。配置域名和策略,第一次返回一个 IP,第二次返回另一个 IP。
全局负载均衡:在北京的同学,想要访问某个网站的某些数据,他应该该网站北京的数据中心服务器;同理,在上海的同学,想要访问某个网站的某些数据,他应该该网站上海的数据中心服务器。
3. Tip
受到这篇文章的启发
https://dave.cheney.net/practical-go/presentations/qcon-china.html
本周阅读了 dave.cheney.net 上一篇关于 Practical Go 的文章
Practical Go: Real world advice for writing maintainable Go programs
实用 Go 指南:编写可维护的 Go 程序的建议
在这篇文章中,作者主要从以下几个方面进行相关叙述
- 指导原则
1.1 简单
1.2 可读性
1.3 生产率 - 标识符
2.1。选择标识符是为了清晰,而不是简洁
2.2。标识符长度
2.3。不要为变量命名变量
2.4。使用一致的命名方式
2.5。使用一致的声明样式
2.6。成为团队合作者 - 评论
3.1。关于变量和常量的注释应描述其内容而非其目的
3.2。始终记录公共符号 - 包装设计
4.1。一个好的包装从它的名字开始
4.2。避免使用诸如 base,common 或 util 之类的包名称
4.3。尽早返回,而不是一直递归
4.4。使零值有用
4.5。避免包级别状态 - 项目结构
5.1。考虑更少,更大的包
5.2。保持包装主要尽可能小 - API设计
6.1。设计难以滥用的API。
6.2。为其默认用例设计API
6.3。让函数定义他们需要的行为 - 错误处理
7.1。通过消除错误消除错误处理
7.2。只处理一次错误 - 并发
8.1。保持忙碌或自己做工作
8.2。将并发性保留给调用者
8.3。如果不知道什么时候停止,就不要开始 goroutine(协程) - 感兴趣的可以访问原网站阅读。
4. Share