提交 642411cd 编写于 作者: C CyC2018

auto commit

上级 3c6be1aa
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册