Skip to content

Commit b47217c

Browse files
author
haolin3
committed
Merge branch 'master' of github.com:geekxh/hello-algorithm
2 parents b28d400 + 2281ea1 commit b47217c

File tree

241 files changed

+3479
-155
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

241 files changed

+3479
-155
lines changed

learning/0.0.学习须知/023.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: 打鸡血
3+
date: 2020-07-12
4+
---
5+
6+
今天的文章,不浪,没图。给大家加加油!
7+
8+
<img src="./023/1.jpg" alt="PNG" style="zoom: 33%;" />
9+
10+
回顾过去一年,京东、知乎、美团、微博、去哪儿、滴滴等。爆出裁员的有多少,虽然最终都被官方辟谣。**但是,你们懂的。**
11+
12+
<br/>
13+
14+
互联网寒冬之下,所有公司都勒紧裤腰带过活。那么,对于个体的你,不努力,不学习,想去大厂?凭什么。
15+
16+
<br/>
17+
18+
请大家原谅我说话的直白。2020年就目前来看,对于企业是明显的买方市场(供过于求)。**而且,未来几年应该都是这样**。所以,大部分企业在招聘时,是要在很多优秀的人中去选出一个更优秀的人,而不是在一群普通人中选择一个优秀的人。
19+
20+
<br/>
21+
22+
毕竟,如果你不够格,可能简历都过不了。**而对于应届生,如果不能多维度的获取你的信息。那么出几道难题,在没有更好的替代方案之前,目前是唯一的选择。**
23+
24+
<br/>
25+
26+
所以我最终很直白的告诉这位同学,刷题,你还是得刷。该记的,你还是得记。尤其如果目标本身就是一个好的offer,那更应是如此。
27+
28+
<br/>
29+
30+
但是,**这样的回答其实是不负责任的**。虽然我考虑到给对方一点压力,很直白的回复了他。但如果放开这一切,我们为什么学算法?为什么学数据结构?
31+
32+
<br/>
33+
34+
“面试造火箭,工作拧螺丝” ,工作四五年,别说红黑树,就连普通二叉树基本都没手写过,**我知道很多人都是这个状态**。这种状态正常吗?**正常**。但不写不等于不用。就算真的不用,也不等于不需要知道怎么用。
35+
36+
<br/>
37+
38+
**其实,很多学生学习数据结构是有问题的**。就这位同学而言,至少出现背代码,就是绝对错误的。数据结构的本质,在我看来是去契合一些应用场景,自然而然的产生,而不是死记硬背。
39+
40+
<br/>
41+
42+
比如说红黑树,我们需要知道这是一种常用的平衡二叉树(或者说特殊的平衡二叉树)知道其对于查找, 插入,删除的复杂度都是log(n) --- n 这里是说树中元素的个数。如果你是java栈,你可能还需要知道 hashmap 为什么选用红黑树来实现。要知道红黑树可以在一些非实时任务调度中,可以高效公平的调度任务。要知道其所有的应用,都是围绕着“平衡”二字。这才是数据结构的核心。
43+
44+
<br/>
45+
46+
至于实现的细枝末节,**知道固然好,但没必要去逼着自己记忆**。因为,我们的职业生涯里,绝对不可能出现让你手写红黑树的节点删除的场景。
47+
48+
<br/>
49+
50+
但你需要知道为什么创造/引入它,它有什么特殊的,它满足哪些场景,又不满足哪些场景,不满足的场景又如何替代。这才是对数据结构的良好理解。
51+
52+
<br/>
53+
54+
其实,除了算法,在我看来很多别的知识也是这样。**只是说算法,更容易在面试的时候去展示而已。本身而言,并没有什么特殊的。**
55+
56+
<br/>
57+
58+
比如学习操作系统。那我们为什么学习操作系统?难道是让我们造出来一个操作系统吗?显而易见并不是。学习操作系统是让我们了解为什么会提出OS,如果没有OS又会是什么样子。它怎么样做任务调度,怎么样做进程管理,怎么样对可用的硬件做成抽象,死锁是如何产生的,内存是怎么管理的,文件系统是如何实现的,通信是指谁与谁的通信。不是说应付了考试就算学了,而是带着脑子掌握这个东西的脉络,这才是核心。
59+
60+
<br/>
61+
62+
比如学习数据库原理,不是说让你去造一个数据库。当然你有这本事,那也ok。更多的是去了解数据库是如何来抽象数据管理的,大数据在什么场景下应运而生。学了之后,你会知道关系型数据库只是数据库中的冰山一角。你知道缓存,索引,批处理,中间件之中都是有着数据库的影子。你用 git 你会知道 .git 文件下,其实就用几个很简单的数据结构,就构建了一个数据库的雏形。你知道事务控制,其实最初只是想把事情做正确,你知道 ACID 是在保证什么。你知道数据库的整个设计中,很多时候我们是在性能和正确性中做选择。你知道除了程序员之外,还有 DBA 更加会关注高可用。你不会再觉得读写分离,主从备份多么高大上,因为你知道除了读写分离之外,还有快慢分离,异地多活,**Replication 和 Failover 很多东东**,都是上个世纪就有了完美的理论支撑。
63+
64+
<br/>
65+
66+
比如学习计算机网络,不是说让你去死记硬背几层网络模型,都各自是什么。而是让你知道全球互联网是如何运作的,知道TCP为了保证数据可靠做了多少额外的工作,握手为什么是3次,不是456次。知道滑动窗口并不等于leetcode上的几道题。知道层与层之间是如何划分的。知道在计算机网络的基础下,还有计算机网络安全一大块基石。
67+
68+
<br/>
69+
70+
比如学习编译原理,没人让你死记硬背那些分词算法。而是去知道为什么要划分词法,语法,语义分析。知道为什么很多语言要提出中间代码这个东东。知道编译原理很多东西,其实就是 NLP 的基础,其实就是智能机器人的基础。知道在 ES 的设计中,其实也参考很多编译器的设计。
71+
72+
<br/>
73+
74+
当然,我们很可能不会完美的掌握上面所说的所有。**但我们会在这个过程中,去发现自己的知识盲点,进而刻意提高**。而不是一直陷入“学不会-理解不了-记不住”的死循环。
75+
76+
<br/>
77+
78+
当然,对于要找工作的人,我们可以直接去击打一些面试痛点,更好的兼容社会。**但我们面试过后,总归是要知识落地,这才能体现你的最终价值。**
79+
80+
<br/>
81+
82+
不要说什么“面试造火箭,工作拧螺丝”,拧螺丝的人,只能一直留在位置上拧螺丝。而努力拧螺丝的人,说不定就有机会去造火箭。而那些有造火箭能力的人,他们终究会造上火箭。

learning/0.0.学习须知/023/1.jpg

538 KB
Loading

learning/1.0.数组系列/009.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
---
2+
title: Z字形变换(6)
3+
date: 2020-07-08
4+
---
5+
6+
> 今天为大家分享一道让很多人头疼过的题目 - Z字形变化。
7+
8+
## 01、题目示例
9+
10+
> 额。。。不知道是不是我瞎,明明是N么(杠精勿扰,只是说说)
11+
12+
<br/>
13+
14+
| 第6题:Z 字形变换 |
15+
| ------------------------------------------------------------ |
16+
| 将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。比如输入字符串为 **"LEETCODEISHIRING" **行数为 3 时,排列如下: |
17+
18+
```
19+
L C I R
20+
E T O E S I I G
21+
E D H N
22+
```
23+
24+
<br/>
25+
26+
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:**"LCIRETOESIIGEDHN"**
27+
28+
<br/>
29+
30+
请你实现这个将字符串进行指定行数变换的函数:
31+
32+
```
33+
string convert(string s, int numRows);
34+
```
35+
36+
**示例 1:**
37+
38+
```
39+
输入: s = "LEETCODEISHIRING", numRows = 3
40+
输出: "LCIRETOESIIGEDHN"
41+
```
42+
43+
**示例 2:**
44+
45+
```
46+
输入: s = "LEETCODEISHIRING", numRows = 4
47+
输出: "LDREOEIIECIHNTSG"
48+
49+
解释:
50+
L D R
51+
E O E I I
52+
E C I H N
53+
T S G
54+
```
55+
56+
<img src="./009/1.gif" alt="PNG" style="zoom: 67%;" />
57+
58+
## 02、题目分析
59+
60+
> 这是我比较推崇的一道“小学题目”,因为其没有任何复杂的思维逻辑,只需要按部就班,就可以顺利解答。难的是,按部就班的过程里,却极其容易出错。
61+
62+
<br/>
63+
64+
因为最终目的是变换字符串的顺序,并且题中也没有限制说不可用额外空间,所以我们秉承不重复造轮子的原则,想办法利用某种结构对原字符串做文章。
65+
66+
<br/>
67+
68+
假若我们采用示例2的数据来进行分析,输入字符串 s 为 "LEETCODEISHIRING", numRows 为 4 ,画成图大概长这样:
69+
70+
<img src="./009/2.jpg" alt="PNG" style="zoom: 50%;" />
71+
72+
重点来了,**我们的目标是按行打印,那总得有个东西来存储每行的数据吧**?因为只需要存储**每行**的数据,那是不是用个数组就可以了。(当然,你硬说搞个map来存也没啥毛病,就是有点闲得蛋疼)
73+
74+
<br/>
75+
76+
问题来了,那数组设置多大呢?自然是有多少行我们就设置多大呗,换句话说,numRows多大,我们的数组就设置多大。画成图大概就是下面这个样子:
77+
78+
<img src="./009/3.jpg" alt="PNG" style="zoom: 50%;" />
79+
80+
存储的容器有了,原字符串也列出来是啥样了,现在嘎哈?自然就是把原字符串放到容器里咯。怎么放?**根据 numRows 的大小来回进行放置即可**(即从0到n-1,再从n-1到0)。具体的请看下图:
81+
82+
<img src="./009/4.jpg" alt="PNG" style="zoom: 67%;" />
83+
84+
上面的图长得不得了,但是观察我们能看出来,**每 2n-2 即为一个周期**。到了这里,应该没有人会质疑这是一道小学题目了吧。。。把所有的字符串放完之后,大概就是下面这个样子:
85+
86+
<img src="./009/5.jpg" alt="PNG" style="zoom: 67%;" />
87+
88+
最后一步,咱们让这个数组排排坐,就可以开始吃果果:
89+
90+
<img src="./009/6.jpg" alt="PNG" style="zoom: 67%;" />
91+
92+
如果看不清楚,不如这样:
93+
94+
<img src="./009/7.jpg" alt="PNG" style="zoom: 67%;" />
95+
96+
根据分析,得出代码(好久没翻go的牌子了):
97+
98+
```go
99+
//go
100+
func convert(s string, numRows int) string {
101+
if numRows == 1{
102+
return s
103+
}
104+
var b = []rune(s)
105+
var res = make([]string, numRows)
106+
var length = len(b)
107+
var period = numRows * 2 - 2
108+
for i := 0 ;i < length; i ++ {
109+
var mod = i % period
110+
if mod < numRows {
111+
res[mod] += string(b[i])
112+
} else {
113+
res[period - mod] += string(b[i])
114+
}
115+
}
116+
return strings.Join(res, "")
117+
}
118+
```
119+
120+
执行结果:
121+
122+
<img src="./009/8.jpg" alt="PNG" style="zoom:;" />
123+
124+
上面的代码要强调两点:
125+
126+
<br/>
127+
128+
第一:用了一个rune,这个其实是go里的用法,用来处理unicode或utf-8字符而已,并没有什么特别的。
129+
130+
第二:12-15行的意思是,在周期内,正着走 numRows-1 下,剩余的反着走。(也就是上面那个长长的图)
131+
132+
<br/>
133+
134+
为了照顾Java的小伙伴,再给出一个Java版本的:
135+
136+
```java
137+
//java
138+
class Solution {
139+
public static String convert(String s, int numRows) {
140+
if (numRows == 1) return s;
141+
String[] arr = new String[numRows];
142+
Arrays.fill(arr, "");
143+
char[] chars = s.toCharArray();
144+
int len = chars.length;
145+
int period = numRows * 2 - 2;
146+
for (int i = 0; i < len; i++) {
147+
int mod = i % period;
148+
if (mod < numRows) {
149+
arr[mod] += chars[i];
150+
} else {
151+
arr[period - mod] += String.valueOf(chars[i]);
152+
}
153+
}
154+
StringBuilder res = new StringBuilder();
155+
for (String ch : arr) {
156+
res.append(ch);
157+
}
158+
return res.toString();
159+
}
160+
}
161+
```
162+
163+
和Go语言的示例一样,代码的关键仍然是计算轨迹的过程(10-17),这里再提供另外一种计算轨迹的方式:
164+
165+
```java
166+
//java
167+
class Solution {
168+
public String convert(String s, int numRows) {
169+
if (numRows == 1) return s;
170+
String[] arr = new String[numRows];
171+
Arrays.fill(arr, "");
172+
int i = 0, flag = -1;
173+
for (char c : s.toCharArray()) {
174+
arr[i] += c;
175+
if (i == 0 || i == numRows - 1) flag = -flag;
176+
i += flag;
177+
}
178+
StringBuilder res = new StringBuilder();
179+
for (String ch : arr) {
180+
res.append(ch);
181+
}
182+
return res.toString();
183+
}
184+
}
185+
```
186+
187+
通过使用一个标志位,来使轨迹回移。(本质其实是一样的)
188+
189+
<br/>
190+
191+
## 03、总结
192+
193+
> 这道题目的意义在于考察coding的能力,本身的思维过程并不复杂。有的同学一看这种题目,**就想通过二维数组来进行计算,殊不知已经落入了题目的陷阱(不信你试试,二维数组出错率一定远胜一维数组)**。当然,本题也是可以不借助额外空间来进行实现的,核心的逻辑完全相同,建议大家下去自己动手练习一下。
194+
195+
<br/>
196+
197+
所以,今天的问题你学会了吗,评论区留下你的想法!
198+

learning/1.0.数组系列/009/1.gif

53.4 KB
Loading

learning/1.0.数组系列/009/2.jpg

10.1 KB
Loading

learning/1.0.数组系列/009/3.jpg

27.2 KB
Loading

learning/1.0.数组系列/009/4.jpg

12.9 KB
Loading

learning/1.0.数组系列/009/5.jpg

17.5 KB
Loading

learning/1.0.数组系列/009/6.jpg

8.53 KB
Loading

learning/1.0.数组系列/009/7.jpg

5.33 KB
Loading

learning/1.0.数组系列/009/8.jpg

4.17 KB
Loading

learning/1.1.链表系列/104.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
---
2+
title: 两数相加(2)
3+
date: 2020-07-09
4+
---
5+
6+
> 前几天写了一篇“小白为了面试如何刷题”的文章大受好评。随之而来的是好多小伙伴私下跑来问我“**浩哥,你说前200道题很好,但是前两百道题的难度很大,我不会怎么办**”这问题我想了一两天。。。好吧,既然你们说难不会。那我干脆就把前两百道题都给你们配上图解,全部安排,这样总可以了吧?牛气冲天有木有,哪个公号主敢这么干的!奥利给,搞起。今儿为大家分享经典面试题目 - 两数相加。做过的朋友,也不要急着叉掉,不妨借机复习一番。
7+
8+
## 01、题目示例
9+
10+
> 各数据结构中的“加减乘除”都是很爱考察的内容。
11+
12+
| 第2题:两数相加 |
13+
| ------------------------------------------------------------ |
14+
| 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 |
15+
16+
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
17+
18+
<br/>
19+
20+
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
21+
22+
<br/>
23+
24+
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
25+
26+
<br/>
27+
28+
**示例:**
29+
30+
```
31+
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
32+
输出:7 -> 0 -> 8
33+
原因:342 + 465 = 807
34+
```
35+
36+
## 02、算法图解
37+
38+
> 烧饼(哨兵)节点:烧饼节点就是说有一个节点长的像烧饼,站在最前面。往往第一个节点小子都会来啃一口,因为是牛肉拔丝烧饼,扯不掉就连起来了。。。好了,我实在编不下去了~囧....
39+
40+
<br/>
41+
42+
不了解哨兵节点的可以看下:
43+
44+
<br/>
45+
46+
[删除链表倒数第N个节点(19)](1.0.数组系列/101.md)
47+
48+
<br/>
49+
50+
好了,了解了哨兵节点,其实这道题和哨兵节点**并没有什么毛线关系,**我只是让你复习一下(会不会想打我)。现在开始正式分析题目。
51+
52+
<br/>
53+
54+
老样子,我们还是先画图,假若我们的链表是 (2 -> 4 -> 3) + (5 -> 6 -> 4) ,大概就是这样(注意,这里我们其实是要完成 342 + 465):
55+
56+
<img src="./104/1.jpg" alt="PNG" style="zoom: 80%;" />
57+
58+
加法肯定是从最低位到最高位进行相加,也就是这里的**链表头到链表尾进行相加,所以需要遍历链表**。我们令 l1 和 l2 指向两个链表的头,用一个 tmp 值来存储同一位相加的结果,以及一个新的链表来存储 tmp 的值。(为什么不直接用新链表存储结果,而是用 tmp 先存储结果,再用新链表存储 tmp 的值呢?请继续往下看)
59+
60+
<img src="./104/2.jpg" alt="PNG" style="zoom: 80%;" />
61+
62+
记住:**所有模拟运算的题目,都需要考虑进位**。这里因为个位不涉及进位,开始计算十位。我们同时遍历 l1,l2,以及新链表到下一位。
63+
64+
<img src="./104/3.jpg" alt="PNG" style="zoom: 80%;" />
65+
66+
重复上面的操作,可以看到十位与个位不同,发生了进位。这时,刚才的 tmp 就有了用武之地。**我们使用 tmp 携带进位的值到下一位的运算**。自然,这里的链表也不能直接存储 tmp 的值了,而是要存储 tmp%10 的值。重复这个步骤,**直到两个链表都遍历完成,并且 tmp 没有进位值**
67+
68+
<img src="./104/4.jpg" alt="PNG" style="zoom: 80%;" />
69+
70+
现在只需要返回我们的新链表就可以了。问题来了,**因为我们没有构造哨兵节点,所以此时不太容易直接返回新链表**。所以在整个流程的第一步,我们还需要用一个哨兵节点指向我们的新链表。
71+
72+
<img src="./104/5.jpg" alt="PNG" style="zoom: 80%;" />
73+
74+
分析完毕,直接上代码(好久没翻Go的牌子了):
75+
76+
```go
77+
//go
78+
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
79+
list := &ListNode{0, nil}
80+
//这里用一个result,只是为了后面返回节点方便,并无他用
81+
result := list
82+
tmp := 0
83+
for l1 != nil || l2 != nil || tmp != 0 {
84+
if l1 != nil {
85+
tmp += l1.Val
86+
l1 = l1.Next
87+
}
88+
if l2 != nil {
89+
tmp += l2.Val
90+
l2 = l2.Next
91+
}
92+
list.Next = &ListNode{tmp % 10, nil}
93+
tmp = tmp / 10
94+
list = list.Next
95+
}
96+
return result.Next
97+
}
98+
```
99+
100+
执行结果:
101+
102+
<img src="./104/6.jpg" alt="PNG" style="zoom: 80%;" />
103+
104+
## 03、总结
105+
106+
> 1950年6月19日,毛泽东写信给当时的教育部部长马叙伦:“要各校注意健康第一,学习第二。营养不足,宜酌增经费。”1951年9月底,毛泽东接见安徽参加国庆的代表团,代表团成员中有渡江小英雄马三姐。毛泽东关切地问她念书情况,还送她一本精美的笔记本,并且在扉页上题词:**好好学习,天天向上**。这8个字的题词迅速在全国传播开来。
107+
108+
<br/>
109+
110+
今天的题目到这里就结束了。你学会了吗?快来评论区留下你的想法吧!
111+

learning/1.1.链表系列/104/1.jpg

16.4 KB
Loading

learning/1.1.链表系列/104/2.jpg

23.6 KB
Loading

learning/1.1.链表系列/104/3.jpg

42.1 KB
Loading

learning/1.1.链表系列/104/4.jpg

43.9 KB
Loading

learning/1.1.链表系列/104/5.jpg

21.3 KB
Loading

learning/1.1.链表系列/104/6.jpg

39.1 KB
Loading

0 commit comments

Comments
 (0)