第 8 周 ARTS

一. Algorithm

本周做了 38. Count and Say 这道题目。开始没看懂题干,后面搞清楚了,从 n=1 开始,对应的字符串为 “1”。然后下一个 n+1 表示的字符串是上一个字符串的读法: 比如 “1” 的读法是一个1,英文为 “one 1”, 也就是 “11”。所以 2 的字符串就是 “11”。而 3 读 “11” 英文是 “two one”,也就是 “21”。其给出了前五个的示例:

1.     1
2.     11
3.     21
4.     1211
5.     111221

讲道理原题给的描述并不怎么清晰,但搞清楚了题目意思就没那么难了(怪不得 Easy 难度)。

从 1 开始,循环读取每一个数字对应的字符串,一直读到 n 即可。
用 Java 实现如下:

class Solution {
   public String countAndSay(int n) {
		
		 // 为 1 的时候直接返回
        String s1 = "1";
        if (n == 1) {
            return s1;
        }

        String s = "";
        s = s1;
        int i = 1;
		 // 循环开始读,一直读到 n
        while (i < n) {
            s = sayString(s);
            i ++;
        }
        return s;

    }

    private String sayString(String preStr) {
     	  // 其实就是个数+数字的拼接
        StringBuffer result = new StringBuffer();
        int length = preStr.length();
        char currnetChar = preStr.charAt(0);
        int currentCharNum = 1;
		        if (length == 1) {
            result.append(currentCharNum);
            result.append(currnetChar);
            return result.toString();
        }
        for (int i = 1; i < length; i ++) {
            char c = preStr.charAt(i);
            if (currnetChar == c) {
                currentCharNum ++;
            } else {
                    result.append(currentCharNum);
                    result.append(currnetChar);
                    currentCharNum = 1;
                    currnetChar = c;
            }

            if (i == length - 1) {
                result.append(currentCharNum);
                result.append(currnetChar);
            }
        }
        return result.toString();
    }
}

最终执行时间 2ms, beats 99.89%。感觉就是一道简单的逻辑题目,想清楚了就行。

二. Review

本周读了 Medium 上的一篇文章 Why I studied full-time for 8 months for a Google interview

作者讲述了自己在 8 个月的时间里学习备战谷歌面试的经历和反思。作者将自己的学习内容整理了一份列表发布到了 Github 上,这是链接 coding-interview-university。 另外在决定去 Google 之前还通过 How Google Works 这本书了解了 Google 的工作。有兴趣的同学可以看下。

文章前半部分作者简要介绍了自己的工作经历和为何选择 Google,后半部分写了自己的感受和反省。初中高中使用过 Basic 语言编程,大学主修经济学并在毕业后进入了军队工作。后来从军队中出来转行做一名 web 开发者并担任过产品经历、市场、CEO 等职位。当作者觉得自己可以胜任任何工作的时候发现自己的技术技能并没有想象中那么厉害,并且了解 Google 的工作方式只会对 Google 非常的感兴趣,因此开始学习并有了上面 Github 中的学习清单。

个人比较有共鸣的是文章的后半部分,首先是作者的感受:

  • 即使最后无法进入 Google,这份经历也是一份非常珍贵的历练。不仅学到了大量过硬的知识,而且让自己有了新的热情去面对任何工作。

很多时候在经历过一段刻苦铭心的努力后,收获到的不仅仅是学到的知识,还有那份静下心来刻苦学习钻研的心性,不断求索的热情,不断提高的学习能力。这是对我们而言是更加珍贵的财富。

另外作者反思了自己的学习方式,最大的问题是:

  • 看了很多不必要的书籍、视频,没有尽快的投入到实际编程中

这一点自己在工作学习中也会经常遇到,很多时候看了很多书籍、视频、文档,虽然概念了解了很多,但因为没有实际上手实践,其实了解的并不透彻,实践出真知。当然在实践到一定阶段后还是要通读相关的文档资料,很多问题都在文档中写清楚了,通览文档使我们对整体细节有一个更加细致的把控,在遇到问题时也能更加的游刃有余。

三. Tip

分享一下使用 Python 快速读写 json 文件的方法吧。
在 Python 中通过 json 库可以直接将 json 文件加载到内存,以及将字典、列表等数据结构直接写到文件中,代码示例如下:

import json
# 加载 json 文件
with open('data.json', 'r') as f:
	data = json.load(f)
	
# 将字典或者列表写入到 json 文件
with open('data.json', 'w') as f:
	data = json.dump(f)

期间可能遇到的一个问题是,如果是数据中文的,在写入文件时所有的中文都会变为如下格式:

["\u65bd\u6167\u73b2", "\u718a\u627f\u6b63"]

因为 json.dump 会默认将非 ascii 码的字符转为\xxxx 的形式,如果想原样输出可以修改参数:

json.dump(shops, f, ensure_ascii=False)

但这样可能遇到一个问题是如果遇到 ascii 不支持的字符会报错,此时要指定使用 utf-8 编码,通过使用 codecs 模块可以实现正常的文件写入

with codecs.open("data.json", 'w', 'utf-8') as f:
	data = json.dump(f)

四. Share

最近开始啃 《TCP/IP 详解卷一: 协议》了,这是第三章 IP: 网际协议 简要笔记。

1. IP 头部

IP 首部通常有 20 (160 位)个字节,主要由如下几部分构成:

  • 版本号: 4 位。目前是4,即 IPv4, 在不久的将来目测就会是 6 了。
  • 首部长度: 4 位。表示首部长度是 32bit 的倍数。因为占 4 位,则最大倍数为 15。 15 * 32bit / 8 = 60。因此 IP 首部的最大长度为 60 字节
  • 服务类型(TOS): 8 位,包括 3bit 优先权字段(现在没卵用了)、4bit 子字段和 1 bit 的必须置 0 的未用位。4 bit 子字段分别为: 最小时延、最大吞吐量、最高可用性、最小费用。只有其中一个可以为 1,都为 0 时为一般服务。大部分 TCP/IP 实现都不支持 TOS 特性
  • 总长度数: 16位,单位是字节。因此 IP 数据报的总长度为 65535 字节。总长度 - IP 首部长度 = 数据的长度。这样可以计算出数据的长度以便当长度不够时对其填充
  • 标识字段:
  • 生存时间(TTL): 8 位。表示可以经过的路由器个数,每经过一个路由减 1。为 0 时数据报就被丢弃。
  • 协议域: 8 位。IP 接收多种协议的数据,因此要在首部标识。1 ICMP 协议、2 IGMP 协议、6 TCP 协议、17 UDP 协议
  • 首部检验和字段: 16 位。根据 IP 首部计算的检验和码。发送方首先将检验和字段设置为 0,然后对首部每个 16bit 进行反码求和,结果存到检验和字段中,接收方再次计算反码求和计算,如果数据没有被改变则计算结果应该全是 1。如果不是表示数据被修改,会丢弃收到的数据报。
  • 源 IP: 32 位
  • 目标 IP: 32 位
  • 任选字段: 是一个可变长的可选信息,字段以 32 bit 作为界限,保证 IP 首部长度为 32bit 的倍数,在必要时会填充 0,一般很少被使用。

2. IP 分类与子网寻址

IP 地址一开始被分为 5 类:

分类 组成 地址范围 最大主机数
A 类 0 + 7 位网络号 + 24 位主机号 0.0.0.0 ~ 127.255.255.255 2^24 - 2
B 类 10 + 14 位网络号 + 16 位主机号 128.0.0.0 ~ 191.255.255.255 2^16 -2 = 65533
C 类 110 + 24 网络号 + 8 位主机号 192.0.0.0 ~ 223.255.255.255
D 类 1110 + 28 位多播组号 224.0.0.0 ~ 239.255.255.255
E 类 11110 + 27 位 240.0.0.0 ~ 255.255.255

以上的 IP 地址划分将 C 类地址可分配的主机数只有 255 台,而 B 类有 6 万多台。这样C 类太少而 B 类太多。在实际需求中一个网络下面的机器可能超过 255,但远远达不到 65533,如果将 IP 闲置未免太过浪费。为解决该问题现在所有主机要求支持子网寻址,其实就是将 32 位地址一分为二,本质上是将原来的主机号再次分为子网号和主机号,也叫做无类型域间选型(CIDR)。

我们可以在拿到某类网络号后确认是否建立子网,例如: 当拿到 140.152 网络号后,为 B 类地址。此时我们可以决定是否建立子网,并为子网分配网络号。如果我们分配 8 位,则其组成为 16 位网络号 + 8 位子网号 + 8 位主机号,则 140.152 网络下就允许有 254 个子网,每个子网有 254 台机器。整体来看位于该网络下的 IP 地址有 24 位网络位 + 8 位主机位,因此 IP 通常表示为: 140.152.1.10/24. 这里的 24 就表示网络位,而根据 140 我们知道其为 B 类网络,本身有 16 位网络号,则子网所占位就是 24 - 16 = 8 位。

主机实际上是通过子网掩码来确定子网数目的。掩码是一个 32bit 的值,1 表示网络号,0 表示主机号。例如上面的子网号为 8bit 的 IP 地址,其子网掩码为

网络号 子网号 主机号 16 进展 点分十进制
11111111 11111111 11111111 00000000 0xffffff00 255.255.255.0

对外部网络来说,其内部子网是透明的,外界只需要知道一个到达 140.152 网络的 IP 即可: 140.152.104.1。到达子网后会比较子网号确认目的 IP 是哪个子网,然后在根据主机号找到对应的主机,完成子网寻址。

另外书中提到了查看网络相关信息的两个命令: ifconfig 与 netstat。熟悉 Linux 的话这两个命令应该不会陌生,这里就不做赘述了, 当然除了这两个还有 ip 命令,也对了解 ip 的操作非常有帮助。

勘误

  • P32 页: 图 3-7 第二幅图中的网络位应为 6 位,原书中印刷成了 8 位。

另外分享一个陈天大神(公众号: 程序人生) 发起的 hackathon ArcBlock 北京黑客松,你来不来?,目测区块链相关还要会前端,作为一个后端弱鸡感觉要去打酱油了 o(╯□╰)o,只为去膜拜大神了 O(∩_∩)O哈哈~

发布了46 篇原创文章 · 获赞 21 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/Ahri_J/article/details/105405136
今日推荐