auto commit
This commit is contained in:
parent
3c6be1aa1e
commit
642411cdc6
|
@ -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 的计算结果进行了向下转型:
|
||||
|
|
|
@ -738,7 +738,7 @@ HashMap 构造函数允许用户传入的容量不是 2 的 n 次方,因为它
|
|||
|
||||
```
|
||||
mask |= mask >> 1 11011000
|
||||
mask |= mask >> 2 11111100
|
||||
mask |= mask >> 2 11111110
|
||||
mask |= mask >> 4 11111111
|
||||
```
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -374,7 +374,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
|||
|
||||
### 2. 连接
|
||||
|
||||
可以将原来的连接分解成多个单表连接查询,然后在用户程序中进行连接。
|
||||
可以将原来的连接分解成多个单表查询,然后在用户程序中进行连接。
|
||||
|
||||
### 3. ID 唯一性
|
||||
|
||||
|
|
|
@ -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 将在环入口点相遇。
|
||||
|
||||
<div align="center"> <img src="../pics//2858f8ad-aedb-45a5-a706-e98c96d690fa.jpg" width="600"/> </div><br>
|
||||
<div align="center"> <img src="../pics//70fa1f83-dae7-456d-b94b-ce28963b2ba1.png"/> </div><br>
|
||||
|
||||
```java
|
||||
public ListNode EntryNodeOfLoop(ListNode pHead) {
|
||||
|
@ -1559,7 +1559,7 @@ public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
|
|||
|
||||
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。假设输入的数组的任意两个数字都互不相同。
|
||||
|
||||
例如,下图是后序遍历序列 3,1,2 所对应的二叉搜索树。
|
||||
例如,下图是后序遍历序列 1,3,2 所对应的二叉搜索树。
|
||||
|
||||
<div align="center"> <img src="../pics//836a4eaf-4798-4e48-b52a-a3dab9435ace.png" width="150"/> </div><br>
|
||||
|
||||
|
|
|
@ -294,12 +294,12 @@ SELECT ... FOR UPDATE;
|
|||
|
||||
----
|
||||
|
||||
| 隔离级别 | 脏读 | 不可重复读 | 幻影读 |
|
||||
| :---: | :---: | :---:| :---: |
|
||||
| 未提交读 | √ | √ | √ |
|
||||
| 提交读 | × | √ | √ |
|
||||
| 可重复读 | × | × | √ |
|
||||
| 可串行化 | × | × | × |
|
||||
| 隔离级别 | 脏读 | 不可重复读 | 幻影读 | 加锁读 |
|
||||
| :---: | :---: | :---:| :---: | :---: |
|
||||
| 未提交读 | √ | √ | √ | × |
|
||||
| 提交读 | × | √ | √ | × |
|
||||
| 可重复读 | × | × | √ | × |
|
||||
| 可串行化 | × | × | × | √ |
|
||||
|
||||
# 五、多版本并发控制
|
||||
|
||||
|
|
|
@ -459,7 +459,7 @@ public abstract class MergeSort<T extends Comparable<T>> extends Sort<T> {
|
|||
|
||||
将一个大数组分成两个小数组去求解。
|
||||
|
||||
因为每次都将问题对半分成两个子问题,而这种对半分的算法复杂度一般为 O(NlogN),因此该归并排序方法的时间复杂度也为 O(NlogN)。
|
||||
因为每次都将问题对半分成两个子问题,这种对半分的算法复杂度一般为 O(NlogN)。
|
||||
|
||||
```java
|
||||
public class Up2DownMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
||||
|
@ -617,7 +617,7 @@ public class ThreeWayQuickSort<T extends Comparable<T>> extends QuickSort<T> {
|
|||
|
||||
可以利用这个特性找出数组的第 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,直到遍历到叶子节点,叶子节点代表的字符的编码就是这个路径编码。
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* [三、扩展性](#三扩展性)
|
||||
* [四、可用性](#四可用性)
|
||||
* [五、安全性](#五安全性)
|
||||
* [参考资料](#参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
|
@ -102,3 +103,7 @@
|
|||
# 五、安全性
|
||||
|
||||
要求系统的应对各种攻击手段时能够有可靠的应对措施。
|
||||
|
||||
# 参考资料
|
||||
|
||||
- 大型网站技术架构:核心原理与案例分析
|
||||
|
|
|
@ -99,7 +99,7 @@ public class LRU<K, V> implements Iterable<K> {
|
|||
|
||||
if (map.size() > maxSize) {
|
||||
Node toRemove = removeTail();
|
||||
map.remove(toRemove);
|
||||
map.remove(toRemove.k);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,7 @@ public class LRU<K, V> implements Iterable<K> {
|
|||
|
||||
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<K, V> implements Iterable<K> {
|
|||
private Node removeTail() {
|
||||
Node node = tail.pre;
|
||||
tail.pre = node.pre;
|
||||
node.pre.next = tail;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
|
@ -1038,7 +1038,7 @@ gcc -o hello hello.c
|
|||
|
||||
## 静态链接
|
||||
|
||||
静态连接器以一组可重定向目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务:
|
||||
静态链接器以一组可重定向目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务:
|
||||
|
||||
- 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。
|
||||
- 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。
|
||||
|
|
|
@ -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);
|
||||
|
|
BIN
pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png
Normal file
BIN
pics/70fa1f83-dae7-456d-b94b-ce28963b2ba1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Loading…
Reference in New Issue
Block a user