Long Luo's Life Notes

每一天都是奇迹

By LongLuo

牛顿有句耳熟能详的名言:“如果我比别人看得远些,那是因为站在巨人肩上的缘故。” 对于每个程序员来说,都希望自己成为一名高手,升职加薪,迎娶白富美,出任CEO,走上人生巅峰。《劝学》里也说“君子生非异也,善假于物也”,告诫我们君子的本性和其他人没有什么不同,只不过是善于利用和借助客观工具, 善于借助外部系统的能量。大神也是从小白过来的,每个小白只要掌握正确的方法,坚持努力,也可以成为大神。

开源项目就是那个巨人,我们可以通过学习开源项目的源码,了解其设计思想,将其应用于我们自己的项目中,吃透其代码,不知不觉中我们的能力也会有大幅度提高。

个人收集了一些很好的Android开源项目,认真学习并掌握,可以大大提升我们的能力。

Android

Google Android开发者官方网站

不用说,Android开发官方权威网站,网站提供的示例和文档值得认真学习和阅读。

https://developer.android.google.cn/

Android Samples

Android官方提供的各种示例和实践,值得认真学习。

https://github.com/android

Android Source Code

在线阅读Android系统源码,提供Android源码的交叉索引,可以快速的搜索符合特定条件的Android源代码,后台是基于OpenGrok引擎,OpenGrok是一个快速,便于使用的源码搜索引擎与对照引擎,它能够帮助我们快速的搜索、定位、对照代码树。

http://androidxref.com/

Github Android Topics

Github 的Android Topics,可以查询到一些Android知名开源项目:

https://github.com/topics/android

Android开源项目汇总

Trinea收集的Android开源项目,内容非常丰富,大家可以各取所需,不过绝大部分偏重于App开发。

https://github.com/Trinea/android-open-project

大前端 跨平台开发

Flutter

官网:https://flutter.dev/

Source Code

架构

architecture-samples

https://github.com/android/architecture-samples

阅读全文 »

By Long Luo

Leetcode 232. 用栈实现队列 ,难度为Easy


  1. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(\(\texttt{push}\)\(\texttt{pop}\)\(\texttt{peek}\)\(\texttt{empty}\)):

实现\(\texttt{MyQueue}\)类:

  • \(\texttt{void push(int x)}\)将元素\(x\)推到队列的末尾
  • \(\texttt{int pop()}\)从队列的开头移除并返回元素
  • \(\texttt{int peek()}\)返回队列开头的元素
  • \(\texttt{boolean empty()}\)如果队列为空,返回\(\textit{true}\);否则,返回\(\textit{false}\)

说明:

你 只能 使用标准的栈操作 —— 也就是只有push to top, peek/pop from top, size, 和is empty操作是合法的。 你所使用的语言也许不支持栈。你可以使用list或者deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用\(100\)\(\texttt{push}\)\(\texttt{pop}\)\(\texttt{peek}\)\(\texttt{empty}\) 假设所有操作都是有效的 (例如,一个空的队列不会调用\(\texttt{pop}\)或者\(\texttt{peek}\)操作)

进阶:

你能否实现每个操作均摊时间复杂度为 \(O(1)\) 的队列?换句话说,执行 \(n\) 个操作的总时间复杂度为 \(O(n)\),即使其中一个操作可能花费较长时间。


之前我们已经实现了 225. 用队列实现栈 ,今天我们来学习如何用队列来实现栈。

因为队列是FIFO,而栈是LIFO,所以我们需要用到两个栈,用其中一个来反转元素的入队顺序,而另一个则用来存储元素的最终顺序。

2个栈 (push - O(n), pop - O(1))

使用 \(2\) 个栈 \(\textit{stack}_1\)\(\textit{stack}_2\)\(\textit{stack}_1\) 作为主栈,而 \(\textit{stack}_2\) 是辅助栈。

入栈时:

  1. \(\textit{stack}_1\) 中所有的元素移到 \(\textit{stack}_2\) 中;
  2. \(\textit{stack}_2\) 中压入新元素;
  3. \(\textit{stack}_2\) 中所有的元素弹出,再把弹出的元素压入 \(\textit{stack}_1\)

代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class MyQueue {
Stack<Integer> stack1;
Stack<Integer> stack2;

public MyQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}

public void push(int x) {
if (stack1.empty()) {
stack1.push(x);
return;
}

while (!stack1.empty()) {
stack2.push(stack1.pop());
}
stack2.push(x);
while (!stack2.empty()) {
stack1.push(stack2.pop());
}
}

public int pop() {
return stack1.pop();
}

public int peek() {
return stack1.peek();
}

public boolean empty() {
return stack1.empty() && stack2.empty();
}
}
阅读全文 »

By Long Luo

Leetcode 225. 用队列实现栈 ,难度为Easy


  1. 用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(\(\texttt{push}\)\(\texttt{top}\)\(\texttt{pop}\)\(\texttt{empty}\))。

实现 \(\texttt{MyStack}\) 类:

  • \(\texttt{void push(int x)}\) 将元素 \(\textit{x}\) 压入栈顶。
  • \(\texttt{int pop()}\) 移除并返回栈顶元素。
  • \(\texttt{int top()}\) 返回栈顶元素。
  • \(\texttt{boolean empty()}\) 如果栈是空的,返回 \(\textit{true}\);否则,返回 \(\textit{false}\)

注意: - 你只能使用队列的基本操作 —— 也就是push to backpeek/pop from frontsizeis empty这些操作。 - 你所使用的语言也许不支持队列。 你可以使用list(列表)或者deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

提示: - 1 <= x <= 9 - 最多调用 \(100\)\(\texttt{push}\)\(\texttt{pop}\)\(\texttt{top}\)\(\texttt{empty}\) - 每次调用 \(\texttt{pop}\)\(\texttt{top}\) 都保证栈不为空

进阶:你能否仅用一个队列来实现栈。


这道题考察的是队列两种数据结构知识。

栈是一种后进先出(LIFO)的数据结构,元素从顶端入栈,然后从顶端出栈。

队列是一种先进先出(FIFO)的数据结构,元素从后端入队,然后从前端出队。

2个队列

题目的要求是用 \(2\) 个队列实现一个栈,但是把一个队列中的数据导入另一个队列中,数据的顺序并没有发生改变,并不会变成先进后出的顺序。

那该如何做呢?

\(2\) 个队列 \(\textit{queue}_1\)\(\textit{queue}_2\)

  1. \(1\) 个元素 \(\textit{A}\),那非常简单,直接压入弹出即可;
  2. \(2\) 个元素 \(\textit{A}\)\(\textit{B}\)\(\textit{queue}_1\) 压入 \(A\)\(\textit{queue}_2\) 压入 \(B\),然后将 \(\textit{queue}_1\) 中元素压入 \(\textit{queue}_2\),这样 \(\textit{queue}_2\) 中的元素顺序就是正确的;
  3. 因为 \(\textit{queue}_1\) 是主队列,所以还需要将 \(\textit{queue}_2\) 中元素重新导入到 \(\textit{queue}_1\)

代码如下所示:

阅读全文 »

By LongLuo

面试时,经常会遇到一道题,说说HTTPS的实现。

为什么需要加密?

HTTPS是为了满足哪些需求?

HTTP的缺点:

  • 通信使用明文(不加密),内容可能会被窃听;
  • 不验证通信方的身份,因此有可能遭遇伪装(中间人攻击);
  • 无法证明报文的完整性,所以有可能已遭篡改。

如何设计HTTPS?

兼容性

因为是先有HTTP再有HTTPS。所以HTTPS首先要考虑到对原有HTTP的兼容性。

兼容性包括多方面,比如已有的Web应用要尽可能无缝地迁移到HTTPS;比如对浏览器厂商而言,改动要尽可能小;……

基于“兼容性”方面的考虑,很容易得出如下几个结论:

  1. HTTPS还是要基于TCP来传输(如果改为UDP作传输层,无论是Web服务端还是浏览器客户端,都要大改——动静太大,伤筋动骨)

  2. 单独使用一个新的协议,把HTTP协议包裹起来(所谓的“HTTP over SSL”,实际上是在原有的HTTP数据外面加了一层SSL的封装。HTTP协议原有的GET、POST之类的机制,基本上原封不动)

打个比方:如果原来的HTTP是塑料水管,容易被戳破;那么如今新设计的HTTPS就像是在原有的塑料水管之外,再包一层金属水管。一来,原有的塑料水管照样运行;二来,用金属加固了之后,不容易被戳破。

可扩展性

前面说了,HTTPS 相当于是“HTTP over SSL”。

如果SSL这个协议在“可扩展性”方面的设计足够牛逼,那么它除了能跟HTTP搭配,还能够跟其它的应用层协议搭配。岂不美哉?

现在看来,当初设计SSL的人确实比较牛。如今的SSL/TLS可以跟很多常用的应用层协议(比如:FTP、SMTP、POP、Telnet)搭配,来强化这些应用层协议的安全性。

接着刚才打的比方:如果把SSL/TLS视作一根用来加固的金属管,它不仅可以用来加固输水的管道,还可以用来加固输煤气的管道。

阅读全文 »
0%