diff --git a/notes/Java 基础.md b/notes/Java 基础.md index 9da25851..eb3572cd 100644 --- a/notes/Java 基础.md +++ b/notes/Java 基础.md @@ -216,7 +216,7 @@ System.out.println(s3 == s4); // true ```java String s5 = "bbb"; String s6 = "bbb"; -System.out.println(s4 == s5); // true +System.out.println(s5 == s6); // true ``` 在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。 @@ -226,9 +226,9 @@ System.out.println(s4 == s5); // true ## new String("abc") -使用这种方式一共会创建两个字符串对象(前提是 String Poll 中还没有 "abc" 字符串对象)。 +使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 "abc" 字符串对象)。 -- "abc" 属于字符串字面量,因此编译时期会在 String Poll 中创建一个字符串对象,指向这个 "abc" 字符串字面量; +- "abc" 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,指向这个 "abc" 字符串字面量; - 而使用 new 的方式会在堆中创建一个字符串对象。 创建一个测试类,其 main 方法中使用这种方式来创建字符串对象。 @@ -267,7 +267,7 @@ Constant pool: // ... ``` -在 Constant Poll 中,#19 存储这字符串字面量 "abc",#3 是 String Poll 的字符串对象,它指向 #19 这个字符串字面量。在 main 方法中,0: 行使用 new #2 在堆中创建一个字符串对象,并且使用 ldc #3 将 String Poll 中的字符串对象作为 String 构造函数的参数。 +在 Constant Pool 中,#19 存储这字符串字面量 "abc",#3 是 String Pool 的字符串对象,它指向 #19 这个字符串字面量。在 main 方法中,0: 行使用 new #2 在堆中创建一个字符串对象,并且使用 ldc #3 将 String Pool 中的字符串对象作为 String 构造函数的参数。 以下是 String 构造函数的源码,可以看到,在将一个字符串对象作为另一个字符串对象的构造函数参数时,并不会完全复制 value 数组内容,而是都会指向同一个 value 数组。 @@ -368,10 +368,11 @@ short s1 = 1; // s1 = s1 + 1; ``` -但是使用 += 运算符可以执行隐式类型转换。 +但是使用 += 或者 ++ 运算符可以执行隐式类型转换。 ```java s1 += 1; +// s1++; ``` 上面的语句相当于将 s1 + 1 的计算结果进行了向下转型: diff --git a/notes/Java 容器.md b/notes/Java 容器.md index 84189928..e42a42f0 100644 --- a/notes/Java 容器.md +++ b/notes/Java 容器.md @@ -738,7 +738,7 @@ HashMap 构造函数允许用户传入的容量不是 2 的 n 次方,因为它 ``` mask |= mask >> 1 11011000 -mask |= mask >> 2 11111100 +mask |= mask >> 2 11111110 mask |= mask >> 4 11111111 ``` diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index 04a751c7..def70c60 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -2420,21 +2420,13 @@ public int climbStairs(int n) { ```java public int rob(int[] nums) { - int n = nums.length; - if (n == 0) { - return 0; - } - if (n == 1) { - return nums[0]; - } - int pre3 = 0, pre2 = 0, pre1 = 0; - for (int i = 0; i < n; i++) { - int cur = Math.max(pre2, pre3) + nums[i]; - pre3 = pre2; + int pre2 = 0, pre1 = 0; + for (int i = 0; i < nums.length; i++) { + int cur = Math.max(pre2 + nums[i], pre1); pre2 = pre1; pre1 = cur; } - return Math.max(pre1, pre2); + return pre1; } ``` @@ -2443,7 +2435,7 @@ public int rob(int[] nums) { [213. House Robber II (Medium)](https://leetcode.com/problems/house-robber-ii/description/) ```java -public int rob(int[] nums) { +public int rob(int[] nums) { if (nums == null || nums.length == 0) { return 0; } @@ -2454,15 +2446,14 @@ public int rob(int[] nums) { return Math.max(rob(nums, 0, n - 2), rob(nums, 1, n - 1)); } -private int rob(int[] nums, int first, int last) { - int pre3 = 0, pre2 = 0, pre1 = 0; +private int rob(int[] nums, int first, int last) { + int pre2 = 0, pre1 = 0; for (int i = first; i <= last; i++) { - int cur = Math.max(pre3, pre2) + nums[i]; - pre3 = pre2; + int cur = Math.max(pre1, pre2 + nums[i]); pre2 = pre1; pre1 = cur; } - return Math.max(pre2, pre1); + return pre1; } ``` @@ -7063,4 +7054,3 @@ public int[] countBits(int num) { - 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014. - 《编程之美》小组. 编程之美[M]. 电子工业出版社, 2008. - 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015. - diff --git a/notes/MySQL.md b/notes/MySQL.md index 2c5d8935..f5479685 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -374,7 +374,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提 ### 2. 连接 -可以将原来的连接分解成多个单表连接查询,然后在用户程序中进行连接。 +可以将原来的连接分解成多个单表查询,然后在用户程序中进行连接。 ### 3. ID 唯一性 diff --git a/notes/剑指 offer 题解.md b/notes/剑指 offer 题解.md index 2c8f2822..e1a87b5b 100644 --- a/notes/剑指 offer 题解.md +++ b/notes/剑指 offer 题解.md @@ -1154,11 +1154,11 @@ public ListNode FindKthToTail(ListNode head, int k) { ## 解题思路 -使用双指针,一个指针 fast 每次移动两个节点,一个指针 slow 每次移动一个节点。因为存在环,所以两个指针必定相遇在环中的某个节点上。假设相遇点在下图的 z1 位置,此时 fast 移动的节点数为 x+2y+z,slow 为 x+y,由于 fast 速度比 slow 快一倍,因此 x+2y+z=2(x+y),得到 x=z。 +使用双指针,一个指针 fast 每次移动两个节点,一个指针 slow 每次移动一个节点。因为存在环,所以两个指针必定相遇在环中的某个节点上。假设相遇点在下图的 y6 位置,此时 fast 移动的节点数为 x+2y+z,slow 为 x+y,由于 fast 速度比 slow 快一倍,因此 x+2y+z=2(x+y),得到 x=z。 在相遇点,slow 要到环的入口点还需要移动 z 个节点,如果让 fast 重新从头开始移动,并且速度变为每次移动一个节点,那么它到环入口点还需要移动 x 个节点。在上面已经推导出 x=z,因此 fast 和 slow 将在环入口点相遇。 -

+

```java public ListNode EntryNodeOfLoop(ListNode pHead) { @@ -1559,7 +1559,7 @@ public ArrayList> Print(TreeNode pRoot) { 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。假设输入的数组的任意两个数字都互不相同。 -例如,下图是后序遍历序列 3,1,2 所对应的二叉搜索树。 +例如,下图是后序遍历序列 1,3,2 所对应的二叉搜索树。

diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index 1bcd2533..1ce774fa 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -294,12 +294,12 @@ SELECT ... FOR UPDATE; ---- -| 隔离级别 | 脏读 | 不可重复读 | 幻影读 | -| :---: | :---: | :---:| :---: | -| 未提交读 | √ | √ | √ | -| 提交读 | × | √ | √ | -| 可重复读 | × | × | √ | -| 可串行化 | × | × | × | +| 隔离级别 | 脏读 | 不可重复读 | 幻影读 | 加锁读 | +| :---: | :---: | :---:| :---: | :---: | +| 未提交读 | √ | √ | √ | × | +| 提交读 | × | √ | √ | × | +| 可重复读 | × | × | √ | × | +| 可串行化 | × | × | × | √ | # 五、多版本并发控制 diff --git a/notes/算法.md b/notes/算法.md index cb83830b..1bc0690a 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -459,7 +459,7 @@ public abstract class MergeSort> extends Sort { 将一个大数组分成两个小数组去求解。 -因为每次都将问题对半分成两个子问题,而这种对半分的算法复杂度一般为 O(NlogN),因此该归并排序方法的时间复杂度也为 O(NlogN)。 +因为每次都将问题对半分成两个子问题,这种对半分的算法复杂度一般为 O(NlogN)。 ```java public class Up2DownMergeSort> extends MergeSort { @@ -617,7 +617,7 @@ public class ThreeWayQuickSort> extends QuickSort { 可以利用这个特性找出数组的第 k 个元素。 -该算法是线性级别的,因为每次能将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然小于 2N。 +该算法是线性级别的,假设每次能将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然小于 2N。 ```java public T select(T[] nums, int k) { @@ -2292,7 +2292,7 @@ from H1 to H3 可以将每种字符转换成二进制编码,例如将 a 转换为 00,b 转换为 01,c 转换为 10,d 转换为 11。这是最简单的一种编码方式,没有考虑各个字符的权值(出现频率)。而哈夫曼编码采用了贪心策略,使出现频率最高的字符的编码最短,从而保证整体的编码长度最短。 -首先生成一颗哈夫曼树,每次生成过程中选取频率最少的两个节点,生成一个新节点作为它们的父节点,并且新节点的频率为两个节点的和。选取频率最少的原因是,生成过程使得先选取的节点在树的最底层,那么需要的编码长度更长,频率更少可以使得总编码长度更少。 +首先生成一颗哈夫曼树,每次生成过程中选取频率最少的两个节点,生成一个新节点作为它们的父节点,并且新节点的频率为两个节点的和。选取频率最少的原因是,生成过程使得先选取的节点位于树的更低层,那么需要的编码长度更长,频率更少可以使得总编码长度更少。 生成编码时,从根节点出发,向左遍历则添加二进制位 0,向右则添加二进制位 1,直到遍历到叶子节点,叶子节点代表的字符的编码就是这个路径编码。 diff --git a/notes/系统设计基础.md b/notes/系统设计基础.md index 4a961140..ffa5de70 100644 --- a/notes/系统设计基础.md +++ b/notes/系统设计基础.md @@ -4,6 +4,7 @@ * [三、扩展性](#三扩展性) * [四、可用性](#四可用性) * [五、安全性](#五安全性) +* [参考资料](#参考资料) @@ -102,3 +103,7 @@ # 五、安全性 要求系统的应对各种攻击手段时能够有可靠的应对措施。 + +# 参考资料 + +- 大型网站技术架构:核心原理与案例分析 diff --git a/notes/缓存.md b/notes/缓存.md index 8f7449bf..07a9e866 100644 --- a/notes/缓存.md +++ b/notes/缓存.md @@ -99,7 +99,7 @@ public class LRU implements Iterable { if (map.size() > maxSize) { Node toRemove = removeTail(); - map.remove(toRemove); + map.remove(toRemove.k); } } @@ -114,6 +114,7 @@ public class LRU implements Iterable { private void appendHead(Node node) { node.next = head.next; + node.next.pre = node; node.pre = head; head.next = node; } @@ -122,6 +123,7 @@ public class LRU implements Iterable { private Node removeTail() { Node node = tail.pre; tail.pre = node.pre; + node.pre.next = tail; return node; } diff --git a/notes/计算机操作系统.md b/notes/计算机操作系统.md index e6c462a6..c0c4364e 100644 --- a/notes/计算机操作系统.md +++ b/notes/计算机操作系统.md @@ -1038,7 +1038,7 @@ gcc -o hello hello.c ## 静态链接 -静态连接器以一组可重定向目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务: +静态链接器以一组可重定向目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务: - 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。 - 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。 diff --git a/notes/设计模式.md b/notes/设计模式.md index d44d0e33..c177ff92 100644 --- a/notes/设计模式.md +++ b/notes/设计模式.md @@ -177,7 +177,7 @@ public class Singleton { #### Ⅵ 枚举实现 - ```java +```java public enum Singleton { INSTANCE; @@ -217,7 +217,7 @@ public enum Singleton { } } } - ``` +``` 该实现在多次序列化再进行反序列化之后,不会得到多个实例。而其它实现,为了保证不会出现反序列化之后出现多个实例,需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。 @@ -276,6 +276,7 @@ public class ConcreteProduct2 implements Product { ```java public class Client { + public static void main(String[] args) { int type = 1; Product product; @@ -295,6 +296,7 @@ public class Client { ```java public class SimpleFactory { + public Product createProduct(int type) { if (type == 1) { return new ConcreteProduct1(); @@ -308,6 +310,7 @@ public class SimpleFactory { ```java public class Client { + public static void main(String[] args) { SimpleFactory simpleFactory = new SimpleFactory(); Product product = simpleFactory.createProduct(1); diff --git a/pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png b/pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png new file mode 100644 index 00000000..0d28e996 Binary files /dev/null and b/pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png differ