你背不下来的书,总有人能背下来;你做不出来的题,总有人能做出来;你愿意拖到明天的事,总有人今天努力做完;那么不好意思,你想去的学校也只能别人去了,你想过的人生也只能别人过了。
路虽然很漫长,很孤单,但是只要你走出一步,你离目的地就近一步,千万不能停在原地叹息,否则永远都无法到达目的地。
Algorithm
没有哪个大牛对数据结构和算法是不熟练的。LeetCode 算法题,至少一题
1. 两数相加
解:主要是对链表的操作,不要漏掉 (5) + (5) ,输出:01 这种情况
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
// 进位
int carry = 0;
ListNode result = new ListNode(0);
ListNode tmp = result;
while (l1 != null || l2 != null || carry != 0) {
int l1Val = l1 != null ? l1.val : 0;
int l2Val = l2 != null ? l2.val : 0;
int sum = l1Val + l2Val + carry;
tmp.next = new ListNode(sum % 10);
tmp = tmp.next;
carry = sum / 10;
l1 = l1 != null ? l1.next : null;
l2 = l2 != null ? l2.next : null;
}
return result.next;
}
2. 无重复字符的最长子串
第一版做了30分钟,然后参考评论进行了优化
解:需要注意临界值的判断
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) {
return 0;
}
if (s.trim().length() == 0) {
return 1;
}
int max = 0;
List result = new ArrayList();
for (int i = 0; i < s.length(); i++) {
char num = s.charAt(i);
if (!result.contains(num)) {
result.add(num);
continue;
}
max = result.size() > max ? result.size() : max;
// 删除前面重复的
Iterator iterator = result.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals(num)) {
iterator.remove();
break;
} else {
iterator.remove();
}
}
result.add(num);
}
return result.size() > max ? result.size() : max;
}
大佬的解法:
public int lengthOfLongestSubstring2(String s) {
// 128 是因为ascii就128个字符
int nums[] = new int[128];
for (int i = 0; i < 128; i++) {
nums[i] = -1;
}
//l是第一个非重复元素的下标。
//cur是当前计数器的值
int l = 0, max = 0, curLen = 0, sLen = s.length();
for (int i = 0; i < sLen; i++) {
// 使用了ascii 码表 https://baike.baidu.com/item/ASCII/309296?fromtitle=ascii%E7%A0%81%E8%A1%A8&fromid=19660475&fr=aladdin 字符转换
// 让int数组的元素和下标都有意义,下标表示:是哪个字符,数组元素表示:在字符串中的下标
int index = s.charAt(i);
if (nums[index] < l) {
nums[index] = i;
curLen++;
} else {
max = curLen > max ? curLen : max;
curLen -= nums[index] - l;
l = nums[index] + 1;
nums[index] = i;
}
}
return curLen > max ? curLen : max;
}
3. 最长回文子串
暴力破解法
就是最简单的循环比较,但是 LeetCode 提升执行超时,提交不了
public String longestPalindrome(String s) {
int len = s.length();
String maxStr = "";
int maxLen = 0;
for (int i = 0; i < len; i++) {
for (int j = i + 1; j <= len; j++) {
String substring = s.substring(i, j);
if (isPalindromic(substring) && substring.length() > maxLen) {
maxLen = substring.length();
maxStr = substring;
}
}
}
return maxStr;
}
/**
* 比较一个字符串是否是回文
* @param s
* @return
*/
public boolean isPalindromic(String s) {
int length = s.length() / 2;
int len = s.length();
for (int i = 0; i < length; i++) {
if (s.charAt(i) != s.charAt(len - i - 1)) {
return false;
}
}
return true;
}
动态规划法
这个算法非常的有名,对我来说还是有难度,之前也看过几次,但没能理解。先m这个解答思路
Review
流畅的阅读英文技术资料是一个大牛必备的。英文学习,以技术翻译为主
“服务器”是难以定义的
最近有人问我什么是服务器,我花了远超于我预期的时间去解释它。我原以为可以给出一个简单的答案,但却没有做到。所以在这里对“服务器”这个词做一些简单的探讨。
服务器是可以对请求做出响应的
一个服务器肯定可以对请求做出响应。例如下列几个例子:
webserver:
Me: "please give me google.com"
Server: "here is the HTML for that webpage"
bittorrent server:
Me: "I would like this chunk of the good wife season 2"
Server: "here are some of the bytes from that .avi file!"
mail server:
Me: "can you send this email to julia@jvns.ca"
Server: "I sent it!"
但是如何精确的描述一个服务器呢?
一个服务器就是一个程序
我的第一反应就是“一个服务器就是一个程序”,因为“wordpress 服务器”就是一个 PHP 程序,所以就从这里开始谈起吧。
一个服务器通常一个程序它在监听着某个端口(例如 80)。举个例子,当我们在谈论一个 Rails web服务时,那么这个程序是是一个 Ruby 程序并且端口上监听着 HTTP 请求。
例如,我们可以启动一个 Python 服务器来服务当前目录之外的文件。
$ python3 -m http.server &
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ..
并且使用 curl
发送一个请求:
$ curl localhost:8000/config.yaml
baseurl: https://jvns.ca
disablePathToLower: true
languageCode: en-us
title: Julia Evans
author: Julia Evans
...
一个服务器可能是一个虚拟机
我们在工作中经常会谈论到“服务器”,通常是这样的一些场景:“我要用 SSH 到那台服务器看看发送了什么事”,或者 “天呐~,这台服务器交换了这个多,太糟糕了!”。
因此在这些情况中,当我说“这个服务器”时很明显它不是一个程序(你不能 SSH 到一个程序上,尽管 SSH 服务器运行在虚拟机上但它本身是一个程序),我指的的是运行服务器程序的 AWS 实例。AWS 实例是一个虚拟机器,在很多方面上看起来是一个计算机(只是一个运行的操作系统!)但是它不是一个物理机。
一个服务器可能是一个容器
类似于你的服务器可能是一个虚拟机。它也可能是运行在虚拟机上的一个容器。因此“这个运行的服务器没有内存了”可能意味着“这容器没有内存并崩溃”,这意味着我们在这个容器上设置 cgroup 内存限制,运行在容器中的程序超过了这个限制,所以 Linux 内核 报 OOM 杀掉了它。
但是容器会让这一切变得更加的复杂,所以我认为我们现在应该停止。
一个服务器是一个计算机
当你从 Dell 或者其它计算机公司购买一个服务器时,你不会去买一个虚拟机,你要买的是一个真正的物理机器。
通常这些计算机会用来构建数据中心。例如,在这个视频中,你可以看到在谷歌数据中心有成千上万的服务器。
在数据中心的计算机不像我们家里的计算机。他们又短又宽,因为它们被设计成可以放进巨大的服务器架中。例如,如果你搜索 Newegg 的 1U 服务器,你会发现服务器是 1“机架单位”高,机架单位是 1.75 英寸。 还有 2U 服务器,它们的高度是 2U 的两倍。
这是一张我再 Newegg 中找到的 1U 服务器:
我只在网络机房中见过一次服务器机架,那里曾经是旧金山的一个教堂,当我使用 Wayback 机器时,我真的觉得很酷,它在使用这个房间里的电脑。
“服务器” 可能是 1000 台电脑
下面,让我们来讨论下 Gmail 是如何工作的。你可能会问“当我搜索我的邮件来找到登机牌时,这是发生在前端还是服务器?”。
答案是“发生在服务器”,但是这里的“服务器”是指什么呢?当搜索你的邮件时,不仅仅是一台计算机、一个程序或者一个虚拟机,谷歌可能用很多的计算机和程序来负责,它们可能分布在世界各个数据中心。
即时我们在讨论做一次搜索,也有可能在 3 个不同的国家有 20 台不同的计算机运行这次搜索。
所以“服务器”这个词在“哦,原来是发生在服务器上”这句话中变的有点复杂——实际上可以说“浏览器发出了一个请求,这个请求做了一些事情,但是我并不担心什么,因为重要的是浏览器发出了一个请求并得到了某种响应。”
当我从邮箱中搜索登机牌时发生了什么?
当我在我的邮箱中搜索“boarding”时,运行在前端的 Javascript 会把它和请求一起发送。虽然很难破解,但是肯定会有“boarding”这个词:
{
"1": {
"1": 79,
"2": 101,
"4": "boarding",
"5": {
"5": 0,
"12": "1577376926313",
"13": -18000000
},
"6": "itemlist-ViewType(79)-5",
"7": 1,
"8": 2000,
"10": 0,
"14": 1,
"16": {
"1": 1,
"2": 0,
"3": 0,
"7": 1
},
"19": 1
},
"3": {
"1": "0",
"2": 5,
"5": 1,
"6": 1,
"7": 1
}
}
我们会得到一个响应返回,这是一个很大且复杂定义好的搜索结果,里面包含了我邮箱中关于登机牌的信息
,这里截取了部分:
"your electronic boarding pass. You could also be asked to display this \nmessage to airport security. * PLEASE NOTE: A printable",
"the attached boarding pass to present at the airport. Manage your booking \nBooking Details Passenger: JULIA EVANS Booking",
"Electronic boarding pass is not offered for your flight. Click the link \nbelow to access the PRINTABLE VERSION of your boarding",
"Save time at the airport Save time at the airport Web version",
"GET YOUR BOARDING PASS IN ADVANCE > You can now check in for your flight \nand you will receive a boarding pass > allowing",
"Save time at the airport Save time at the airport Web version",
"Booking Confirmation Booking Reference: xxxxxx Date of issue: xxxxxxxxxxxx \nSelect Seats eUpgrade",
"your electronic boarding pass. You could also be asked to display this \nmessage to airport security. * PLEASE NOTE: A printable",
"your electronic boarding pass. You could also be asked to display this \nmessage to airport security. * PLEASE NOTE: A printable",
"Save time at the airport Save time at the airport Web version",
"house was boarded up during the last round of bombings. I have no spatial \nimagination and cannot picture the house in three",
"Booking Confirmation Booking Reference: xxxxxx Date of issue: xxxxxxxxxxxx \nSelect Seats eUpgrade"
"required when boarding a flight to Canada. For more details, please visit \nCanada.ca/eTA . - Terms and Conditions of Sale",
"Your KLM boarding pass(s) on XXXXXX To: [image: KLM SkyTeam] Boarding \ninformation Thank you for checking in! Attached you",
"Boarding information Thank you for checking in! Attached you will find your \nboarding pass and/or other documents. Below",
"jetBlue® Your upcoming trip to SEATTLE, WA on xxxxxxxxxxx Flight status \nBaggage info Airport info TAG",
"your electronic boarding pass. You could also be asked to display this \nmessage to airport security. * PLEASE NOTE: A printable"
这个请求发送到 172.217.13.197:443,它对应我附近某个边缘服务器,除了第一个收到我请求的,可能还有其他很多计算机参与搜索我的邮件,但这其中的好处是我们不需要关心幕后到底发生了什么!浏览器发送了一个请求,它得到了搜索结果,它不需要知道什么服务器。
我们只需要说“这发生在服务器”,不要太担心这到底是什么意思(知道发生奇怪的事情:))。
“服务器”的意思取决于上下文
所以我们到了一个有意思的地方——起点。当我思考关于“什么是服务器?” 我真的以为这是一个简单的答案。但事实证明,如果你看我们使用“服务器”这个词的句子,它实际上可以值很多不同的事务,这会让人疑惑:
- “让我用 ssh 连接到服务器看看发生了什么” => 一个虚拟机或是一台计算机
- “我发送了一个 SIGTERM 到服务器并且修复了这个问题” => 一个程序
- “让我看看服务器上的代码” => 一个程序
- “让我们购买 20 台 2U 的服务器” => 一台计算机
- “我们需要添加更多的服务器数量 ”=> 一个程序 或者是 虚拟机
- “这发送在服务端” => 可能是一些复杂的分布式系统
Tip
保持好奇,保持学习。至少一个技巧,以技术技巧为主
如果发布在服务器的代码和你预想的不一致,可以使用阿里的 arthas,其中的 jad 命令可以反编译指定已加载类的源码。
这是一个 Java 编写的工具,
- 首先需要下载 arthas.jar
- 然后运行 java -jar arthas.jar
- 输入数字,选择你要反编译的你那个 Java 应用
- 然后对指定类反编译
例子使用,这里反编译 String 这个类:
$ jad java.lang.String
---------------一以下是输出结果:-------------------
ClassLoader:
Location:
/*
* Decompiled with CFR 0_132.
*/
package java.lang;
import java.io.ObjectStreamField;
...
public final class String
implements Serializable,
Comparable<String>,
CharSequence {
private final char[] value;
private int hash;
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
public String(byte[] arrby, int n, int n2) {
String.checkBounds(arrby, n, n2);
this.value = StringCoding.decode(arrby, n, n2);
}
...
也可以反编译指定类的函数:
$ jad java.lang.String length
略...
更多使用参考官网
Share
要是为了建立你的影响力,能够输出价值观。分享一篇有观点和思考的文章,也可以是技术总结的文章。
读书《贫穷的本质》