auto commit

This commit is contained in:
CyC2018 2019-11-02 14:39:13 +08:00
parent f77756272b
commit 058e67e0ff
159 changed files with 3185 additions and 839 deletions

View File

@ -8,13 +8,13 @@
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?f(n)=\left\{\begin{array}{rcl}0&&{n=0}\\1&&{n=1}\\f(n-1)+f(n-2)&&{n>1}\end{array}\right." class="mathjax-pic"/></div> <br> -->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/45be9587-6069-4ab7-b9ac-840db1a53744.jpg" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/45be9587-6069-4ab7-b9ac-840db1a53744.jpg" width="300px"> </div><br>
## 解题思路
如果使用递归求解会重复计算一些子问题例如计算 f(4) 需要计算 f(3) f(2)计算 f(3) 需要计算 f(2) f(1)可以看到 f(2) 被重复计算了
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c13e2a3d-b01c-4a08-a69b-db2c4e821e09.png" width="350px"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c13e2a3d-b01c-4a08-a69b-db2c4e821e09.png" width="350px"/> </div><br>
递归是将一个问题划分成多个子问题求解动态规划也是如此但是动态规划会把子问题的解缓存起来从而避免重复求解子问题
@ -65,3 +65,10 @@ public class Solution {
}
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,23 +6,23 @@
我们可以用 2\*1 的小矩形横着或者竖着去覆盖更大的矩形请问用 n 2\*1 的小矩形无重叠地覆盖一个 2\*n 的大矩形总共有多少种方法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/b903fda8-07d0-46a7-91a7-e803892895cf.gif" width="100px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/b903fda8-07d0-46a7-91a7-e803892895cf.gif" width="100px"> </div><br>
## 解题思路
n 1 只有一种覆盖方法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f6e146f1-57ad-411b-beb3-770a142164ef.png" width="100px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f6e146f1-57ad-411b-beb3-770a142164ef.png" width="100px"> </div><br>
n 2 有两种覆盖方法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/fb3b8f7a-4293-4a38-aae1-62284db979a3.png" width="200px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/fb3b8f7a-4293-4a38-aae1-62284db979a3.png" width="200px"> </div><br>
要覆盖 2\*n 的大矩形可以先覆盖 2\*1 的矩形再覆盖 2\*(n-1) 的矩形或者先覆盖 2\*2 的矩形再覆盖 2\*(n-2) 的矩形而覆盖 2\*(n-1) 2\*(n-2) 的矩形可以看成子问题该问题的递推公式如下
<!-- <div align="center"><img src="https://latex.codecogs.com/gif.latex?f(n)=\left\{\begin{array}{rcl}1&&{n=1}\\2&&{n=2}\\f(n-1)+f(n-2)&&{n>1}\end{array}\right." class="mathjax-pic"/></div> <br> -->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/508c6e52-9f93-44ed-b6b9-e69050e14807.jpg" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/508c6e52-9f93-44ed-b6b9-e69050e14807.jpg" width="350px"> </div><br>
```java
public int RectCover(int n) {
@ -38,3 +38,10 @@ public int RectCover(int n) {
return result;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,21 +6,21 @@
一只青蛙一次可以跳上 1 级台阶也可以跳上 2 求该青蛙跳上一个 n 级的台阶总共有多少种跳法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9dae7475-934f-42e5-b3b3-12724337170a.png" width="380px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9dae7475-934f-42e5-b3b3-12724337170a.png" width="380px"> </div><br>
## 解题思路
n = 1 只有一种跳法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/72aac98a-d5df-4bfa-a71a-4bb16a87474c.png" width="250px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/72aac98a-d5df-4bfa-a71a-4bb16a87474c.png" width="250px"> </div><br>
n = 2 有两种跳法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1b80288d-1b35-4cd3-aa17-7e27ab9a2389.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1b80288d-1b35-4cd3-aa17-7e27ab9a2389.png" width="300px"> </div><br>
n 阶台阶可以先跳 1 阶台阶再跳 n-1 阶台阶或者先跳 2 阶台阶再跳 n-2 阶台阶 n-1 n-2 阶台阶的跳法可以看成子问题该问题的递推公式为
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/508c6e52-9f93-44ed-b6b9-e69050e14807.jpg" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/508c6e52-9f93-44ed-b6b9-e69050e14807.jpg" width="350px"> </div><br>
```java
public int JumpFloor(int n) {
@ -36,3 +36,10 @@ public int JumpFloor(int n) {
return result;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
一只青蛙一次可以跳上 1 级台阶也可以跳上 2 ... 它也可以跳上 n 求该青蛙跳上一个 n 级的台阶总共有多少种跳法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/cd411a94-3786-4c94-9e08-f28320e010d5.png" width="380px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/cd411a94-3786-4c94-9e08-f28320e010d5.png" width="380px"> </div><br>
## 解题思路
@ -56,3 +56,10 @@ public int JumpFloorII(int target) {
return (int) Math.pow(2, target - 1);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,13 +6,13 @@
把一个数组最开始的若干个元素搬到数组的末尾我们称之为数组的旋转输入一个非递减排序的数组的一个旋转输出旋转数组的最小元素
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0038204c-4b8a-42a5-921d-080f6674f989.png" width="210px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0038204c-4b8a-42a5-921d-080f6674f989.png" width="210px"> </div><br>
## 解题思路
将旋转数组对半分可以得到一个包含最小元素的新旋转数组以及一个非递减排序的数组新的旋转数组的数组元素是原数组的一半从而将问题规模减少了一半这种折半性质的算法的时间复杂度为 O(logN)为了方便这里将 log<sub>2</sub>N 写为 logN
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/424f34ab-a9fd-49a6-9969-d76b42251365.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/424f34ab-a9fd-49a6-9969-d76b42251365.png" width="300px"> </div><br>
此时问题的关键在于确定对半分得到的两个数组哪一个是旋转数组哪一个是非递减数组我们很容易知道非递减数组的第一个元素一定小于等于最后一个元素
@ -63,3 +63,10 @@ private int minNumber(int[] nums, int l, int h) {
return nums[l];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -8,13 +8,13 @@
例如下面的矩阵包含了一条 bfce 路径
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1db1c7ea-0443-478b-8df9-7e33b1336cc4.png" width="200px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1db1c7ea-0443-478b-8df9-7e33b1336cc4.png" width="200px"> </div><br>
## 解题思路
使用回溯法backtracking进行求解它是一种暴力搜索方法通过搜索所有可能的结果来求解问题回溯法在一次搜索结束时需要进行回溯回退将这一次搜索过程中设置的状态进行清除从而开始一次新的搜索过程例如下图示例中 f 开始下一步有 4 种搜索可能如果先搜索 b需要将 b 标记为已经使用防止重复使用在这一次搜索结束之后需要将 b 的已经使用状态清除并搜索 c
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dc964b86-7a08-4bde-a3d9-e6ddceb29f98.png" width="200px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dc964b86-7a08-4bde-a3d9-e6ddceb29f98.png" width="200px"> </div><br>
本题的输入是数组而不是矩阵二维数组因此需要先将数组转换成矩阵
@ -62,3 +62,10 @@ private char[][] buildMatrix(char[] array) {
return matrix;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -56,3 +56,10 @@ private void initDigitSum() {
this.digitSum[i][j] = digitSumOne[i] + digitSumOne[j];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -50,3 +50,10 @@ public int integerBreak(int n) {
return dp[n];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -38,3 +38,10 @@ public int NumberOf1(int n) {
return Integer.bitCount(n);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -12,7 +12,7 @@
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?x^n=\left\{\begin{array}{rcl}(x*x)^{n/2}&&{n\%2=0}\\x*(x*x)^{n/2}&&{n\%2=1}\end{array}\right." class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/48b1d459-8832-4e92-938a-728aae730739.jpg" width="330px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/48b1d459-8832-4e92-938a-728aae730739.jpg" width="330px"> </div><br>
因为 (x\*x)<sup>n/2</sup> 可以通过递归求解并且每次递归 n 都减小一半因此整个算法的时间复杂度为 O(logN)
@ -34,3 +34,10 @@ public double Power(double base, int exponent) {
return isNegative ? 1 / pow : pow;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -38,3 +38,10 @@ private void printNumber(char[] number) {
System.out.println();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -4,11 +4,11 @@
如果该节点不是尾节点那么可以直接将下一个节点的值赋给该节点然后令该节点指向下下个节点再删除下一个节点时间复杂度为 O(1)
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1176f9e1-3442-4808-a47a-76fbaea1b806.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1176f9e1-3442-4808-a47a-76fbaea1b806.png" width="600"/> </div><br>
否则就需要先遍历链表找到节点的前一个节点然后让前一个节点指向 null时间复杂度为 O(N)
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/4bf8d0ba-36f0-459e-83a0-f15278a5a157.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/4bf8d0ba-36f0-459e-83a0-f15278a5a157.png" width="600"/> </div><br>
综上如果进行 N 次操作那么大约需要操作节点的次数为 N-1+N=2N-1其中 N-1 表示 N-1 个不是尾节点的每个节点以 O(1) 的时间复杂度操作节点的总次数N 表示 1 个尾节点以 O(N) 的时间复杂度操作节点的总次数(2N-1)/N \~ 2因此该算法的平均时间复杂度为 O(1)
@ -35,3 +35,10 @@ public ListNode deleteNode(ListNode head, ListNode tobeDelete) {
return head;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -4,7 +4,7 @@
## 题目描述
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/17e301df-52e8-4886-b593-841a16d13e44.png" width="450"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/17e301df-52e8-4886-b593-841a16d13e44.png" width="450"/> </div><br>
## 解题描述
@ -23,3 +23,10 @@ public ListNode deleteDuplication(ListNode pHead) {
}
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -38,3 +38,10 @@ public boolean match(char[] str, char[] pattern) {
return dp[m][n];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -47,3 +47,10 @@ public boolean isNumeric(char[] str) {
return new String(str).matches("[+-]?\\d*(\\.\\d+)?([eE][+-]?\\d+)?");
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
需要保证奇数和奇数偶数和偶数之间的相对位置不变这和书本不太一样
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d03a2efa-ef19-4c96-97e8-ff61df8061d3.png" width="200px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d03a2efa-ef19-4c96-97e8-ff61df8061d3.png" width="200px"> </div><br>
## 解题思路
@ -58,3 +58,10 @@ private void swap(int[] nums, int i, int j) {
nums[j] = t;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
设链表的长度为 N设置两个指针 P1 P2先让 P1 移动 K 个节点则还有 N - K 个节点可以移动此时让 P1 P2 同时移动可以知道当 P1 移动到链表结尾时P2 移动到第 N - K 个节点处该位置就是倒数第 K 个节点
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6b504f1f-bf76-4aab-a146-a9c7a58c2029.png" width="500"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6b504f1f-bf76-4aab-a146-a9c7a58c2029.png" width="500"/> </div><br>
```java
public ListNode FindKthToTail(ListNode head, int k) {
@ -25,3 +25,10 @@ public ListNode FindKthToTail(ListNode head, int k) {
return P2;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -12,7 +12,7 @@
在相遇点slow 要到环的入口点还需要移动 z 个节点如果让 fast 重新从头开始移动并且速度变为每次移动一个节点那么它到环入口点还需要移动 x 个节点在上面已经推导出 x=z因此 fast slow 将在环入口点相遇
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/bb7fc182-98c2-4860-8ea3-630e27a5f29f.png" width="500"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/bb7fc182-98c2-4860-8ea3-630e27a5f29f.png" width="500"/> </div><br>
```java
public ListNode EntryNodeOfLoop(ListNode pHead) {
@ -31,3 +31,10 @@ public ListNode EntryNodeOfLoop(ListNode pHead) {
return slow;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -34,3 +34,10 @@ public ListNode ReverseList(ListNode head) {
return newList.next;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -4,7 +4,7 @@
## 题目描述
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c094d2bc-ec75-444b-af77-d369dfb6b3b4.png" width="400"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c094d2bc-ec75-444b-af77-d369dfb6b3b4.png" width="400"/> </div><br>
## 解题思路
@ -49,3 +49,10 @@ public ListNode Merge(ListNode list1, ListNode list2) {
return head.next;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -4,7 +4,7 @@
## 题目描述
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/84a5b15a-86c5-4d8e-9439-d9fd5a4699a1.jpg" width="450"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/84a5b15a-86c5-4d8e-9439-d9fd5a4699a1.jpg" width="450"/> </div><br>
## 解题思路
@ -25,3 +25,10 @@ private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) {
return isSubtreeWithRoot(root1.left, root2.left) && isSubtreeWithRoot(root1.right, root2.right);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -4,7 +4,7 @@
## 题目描述
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0c12221f-729e-4c22-b0ba-0dfc909f8adf.jpg" width="300"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0c12221f-729e-4c22-b0ba-0dfc909f8adf.jpg" width="300"/> </div><br>
## 解题思路
@ -23,3 +23,10 @@ private void swap(TreeNode root) {
root.right = t;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -4,7 +4,7 @@
## 题目描述
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0c12221f-729e-4c22-b0ba-0dfc909f8adf.jpg" width="300"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0c12221f-729e-4c22-b0ba-0dfc909f8adf.jpg" width="300"/> </div><br>
## 解题思路
@ -25,3 +25,10 @@ boolean isSymmetrical(TreeNode t1, TreeNode t2) {
return isSymmetrical(t1.left, t2.right) && isSymmetrical(t1.right, t2.left);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
下图的矩阵顺时针打印结果为1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/48517227-324c-4664-bd26-a2d2cffe2bfe.png" width="200px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/48517227-324c-4664-bd26-a2d2cffe2bfe.png" width="200px"> </div><br>
## 解题思路
@ -30,3 +30,10 @@ public ArrayList<Integer> printMatrix(int[][] matrix) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -24,7 +24,7 @@ Output:
(2, 3, 1, 0, 2, 5) 为例遍历到位置 4 该位置上的数为 2但是第 2 个位置上已经有一个 2 的值了因此可以知道 2 重复
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/643b6f18-f933-4ac5-aa7a-e304dbd7fe49.gif" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/643b6f18-f933-4ac5-aa7a-e304dbd7fe49.gif" width="350px"> </div><br>
```java
@ -49,3 +49,10 @@ private void swap(int[] nums, int i, int j) {
nums[j] = t;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -30,3 +30,10 @@ public int min() {
return minStack.peek();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -27,3 +27,10 @@ public boolean IsPopOrder(int[] pushSequence, int[] popSequence) {
return stack.isEmpty();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -8,7 +8,7 @@
例如以下二叉树层次遍历的结果为1,2,3,4,5,6,7
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d5e838cf-d8a2-49af-90df-1b2a714ee676.jpg" width="250"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d5e838cf-d8a2-49af-90df-1b2a714ee676.jpg" width="250"/> </div><br>
## 解题思路
@ -35,3 +35,10 @@ public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -30,3 +30,10 @@ ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -34,3 +34,10 @@ public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -8,7 +8,7 @@
例如下图是后序遍历序列 1,3,2 所对应的二叉搜索树
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/13454fa1-23a8-4578-9663-2b13a6af564a.jpg" width="150"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/13454fa1-23a8-4578-9663-2b13a6af564a.jpg" width="150"/> </div><br>
## 解题思路
@ -32,3 +32,10 @@ private boolean verify(int[] sequence, int first, int last) {
return verify(sequence, first, cutIndex - 1) && verify(sequence, cutIndex, last - 1);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -8,7 +8,7 @@
下图的二叉树有两条和为 22 的路径10, 5, 7 10, 12
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ed77b0e6-38d9-4a34-844f-724f3ffa2c12.jpg" width="200"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ed77b0e6-38d9-4a34-844f-724f3ffa2c12.jpg" width="200"/> </div><br>
## 解题思路
@ -34,3 +34,10 @@ private void backtracking(TreeNode node, int target, ArrayList<Integer> path) {
path.remove(path.size() - 1);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -18,21 +18,21 @@ public class RandomListNode {
}
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/66a01953-5303-43b1-8646-0c77b825e980.png" width="300"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/66a01953-5303-43b1-8646-0c77b825e980.png" width="300"/> </div><br>
## 解题思路
第一步在每个节点的后面插入复制的节点
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dfd5d3f8-673c-486b-8ecf-d2082107b67b.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dfd5d3f8-673c-486b-8ecf-d2082107b67b.png" width="600"/> </div><br>
第二步对复制节点的 random 链接进行赋值
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/cafbfeb8-7dfe-4c0a-a3c9-750eeb824068.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/cafbfeb8-7dfe-4c0a-a3c9-750eeb824068.png" width="600"/> </div><br>
第三步拆分
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e151b5df-5390-4365-b66e-b130cd253c12.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e151b5df-5390-4365-b66e-b130cd253c12.png" width="600"/> </div><br>
```java
public RandomListNode Clone(RandomListNode pHead) {
@ -65,3 +65,10 @@ public RandomListNode Clone(RandomListNode pHead) {
return pCloneHead;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
输入一棵二叉搜索树将该二叉搜索树转换成一个排序的双向链表要求不能创建任何新的结点只能调整树中结点指针的指向
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/05a08f2e-9914-4a77-92ef-aebeaecf4f66.jpg" width="400"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/05a08f2e-9914-4a77-92ef-aebeaecf4f66.jpg" width="400"/> </div><br>
## 解题思路
@ -32,3 +32,10 @@ private void inOrder(TreeNode node) {
inOrder(node.right);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -37,3 +37,10 @@ private TreeNode Deserialize() {
return t;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -38,3 +38,10 @@ private void backtracking(char[] chars, boolean[] hasUsed, StringBuilder s) {
}
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -25,3 +25,10 @@ public int MoreThanHalfNum_Solution(int[] nums) {
return cnt > nums.length / 2 ? majority : 0;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -28,7 +28,7 @@ Given target = 20, return false.
该二维数组中的一个数小于它的数一定在其左边大于它的数一定在其下边因此从右上角开始查找就可以根据 target 和当前元素的大小关系来缩小查找区间当前元素的查找区间为左下角的所有元素
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/35a8c711-0dc0-4613-95f3-be96c6c6e104.gif" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/35a8c711-0dc0-4613-95f3-be96c6c6e104.gif" width="400px"> </div><br>
```java
public boolean Find(int target, int[][] matrix) {
@ -47,3 +47,10 @@ public boolean Find(int target, int[][] matrix) {
return false;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -79,3 +79,10 @@ public ArrayList<Integer> GetLeastNumbers_Solution(int[] nums, int k) {
return new ArrayList<>(maxHeap);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -38,3 +38,10 @@ public Double GetMedian() {
return (double) right.peek();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -23,3 +23,10 @@ public char FirstAppearingOnce() {
return queue.isEmpty() ? '#' : queue.peek();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -22,3 +22,10 @@ public int FindGreatestSumOfSubArray(int[] nums) {
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -16,3 +16,10 @@ public int NumberOf1Between1AndN_Solution(int n) {
```
> [Leetcode : 233. Number of Digit One](https://leetcode.com/problems/number-of-digit-one/discuss/64381/4+-lines-O(log-n)-C++JavaPython)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -52,3 +52,10 @@ private int getDigitAtIndex(int index, int place) {
return number.charAt(count) - '0';
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -25,3 +25,10 @@ public String PrintMinNumber(int[] numbers) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -29,3 +29,10 @@ public int numDecodings(String s) {
return dp[n];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -33,3 +33,10 @@ public int getMost(int[][] values) {
return dp[n - 1];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -27,3 +27,10 @@ public int longestSubStringWithoutDuplication(String str) {
return maxLen;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -28,3 +28,10 @@ public int GetUglyNumber_Solution(int N) {
return dp[N - 1];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -23,7 +23,7 @@ Output:
从后向前遍是为了在改变 P2 所指向的内容时不会影响到 P1 遍历原来字符串的内容
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6980aef0-debe-4b4b-8da5-8b1befbc1408.gif" width="230px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6980aef0-debe-4b4b-8da5-8b1befbc1408.gif" width="230px"> </div><br>
```java
public String replaceSpace(StringBuffer str) {
@ -46,3 +46,10 @@ public String replaceSpace(StringBuffer str) {
return str.toString();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -47,3 +47,10 @@ public int FirstNotRepeatingChar2(String str) {
return -1;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -46,3 +46,10 @@ private void merge(int[] nums, int l, int m, int h) {
nums[k] = tmp[k];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -4,7 +4,7 @@
## 题目描述
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5f1cb999-cb9a-4f6c-a0af-d90377295ab8.png" width="500"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5f1cb999-cb9a-4f6c-a0af-d90377295ab8.png" width="500"/> </div><br>
## 解题思路
@ -22,3 +22,10 @@ public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
return l1;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -34,3 +34,10 @@ private int binarySearch(int[] nums, int K) {
return l;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -25,3 +25,10 @@ private void inOrder(TreeNode root, int k) {
inOrder(root.right, k);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
从根结点到叶结点依次经过的结点含根叶结点形成树的一条路径最长路径的长度为树的深度
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ba355101-4a93-4c71-94fb-1da83639727b.jpg" width="350px"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ba355101-4a93-4c71-94fb-1da83639727b.jpg" width="350px"/> </div><br>
## 解题思路
@ -15,3 +15,10 @@ public int TreeDepth(TreeNode root) {
return root == null ? 0 : 1 + Math.max(TreeDepth(root.left), TreeDepth(root.right));
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
平衡二叉树左右子树高度差不超过 1
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/af1d1166-63af-47b6-9aa3-2bf2bd37bd03.jpg" width="250px"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/af1d1166-63af-47b6-9aa3-2bf2bd37bd03.jpg" width="250px"/> </div><br>
## 解题思路
@ -28,3 +28,10 @@ private int height(TreeNode root) {
return 1 + Math.max(left, right);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -26,3 +26,10 @@ public void FindNumsAppearOnce(int[] nums, int num1[], int num2[]) {
}
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -29,3 +29,10 @@ public ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {
return new ArrayList<>();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -41,3 +41,10 @@ public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -45,3 +45,10 @@ private void swap(char[] c, int i, int j) {
c[j] = t;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -39,3 +39,10 @@ private void swap(char[] chars, int i, int j) {
chars[j] = t;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -27,3 +27,10 @@ public ArrayList<Integer> maxInWindows(int[] num, int size) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
从尾到头反过来打印出每个结点的值
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f5792051-d9b2-4ca4-a234-a4a2de3d5a57.png" width="280px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f5792051-d9b2-4ca4-a234-a4a2de3d5a57.png" width="280px"> </div><br>
## 解题思路
@ -34,7 +34,7 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
- 头结点是在头插法中使用的一个额外节点这个节点不存储值
- 第一个节点就是链表的第一个真正存储值的节点
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0dae7e93-cfd1-4bd3-97e8-325b032b716f.gif" width="370px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0dae7e93-cfd1-4bd3-97e8-325b032b716f.gif" width="370px"> </div><br>
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
@ -61,7 +61,7 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
栈具有后进先出的特点在遍历链表时将值按顺序放入栈中最后出栈的顺序即为逆序
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9d1deeba-4ae1-41dc-98f4-47d85b9831bc.gif" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9d1deeba-4ae1-41dc-98f4-47d85b9831bc.gif" width="300px"> </div><br>
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
@ -76,3 +76,10 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
n 个骰子扔在地上求点数和为 s 的概率
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/195f8693-5ec4-4987-8560-f25e365879dd.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/195f8693-5ec4-4987-8560-f25e365879dd.png" width="300px"> </div><br>
## 解题思路
@ -70,3 +70,10 @@ public List<Map.Entry<Integer, Double>> dicesSum(int n) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
五张牌其中大小鬼为癞子牌面为 0判断这五张牌是否能组成顺子
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/eaa506b6-0747-4bee-81f8-3cda795d8154.png" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/eaa506b6-0747-4bee-81f8-3cda795d8154.png" width="350px"> </div><br>
## 解题思路
@ -35,3 +35,10 @@ public boolean isContinuous(int[] nums) {
return cnt >= 0;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -19,3 +19,10 @@ public int LastRemaining_Solution(int n, int m) {
return (LastRemaining_Solution(n - 1, m) + m) % n;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
可以有一次买入和一次卖出买入必须在前求最大收益
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/42661013-750f-420b-b3c1-437e9a11fb65.png" width="220px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/42661013-750f-420b-b3c1-437e9a11fb65.png" width="220px"> </div><br>
## 解题思路
@ -25,3 +25,10 @@ public int maxProfit(int[] prices) {
return maxProfit;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -21,3 +21,10 @@ public int Sum_Solution(int n) {
return sum;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -17,3 +17,10 @@ public int Add(int a, int b) {
return b == 0 ? a : Add(a ^ b, (a & b) << 1);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -6,7 +6,7 @@
给定一个数组 A[0, 1,..., n-1]请构建一个数组 B[0, 1,..., n-1]其中 B 中的元素 B[i]=A[0]\*A[1]\*...\*A[i-1]\*A[i+1]\*...\*A[n-1]要求不能使用除法
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/4240a69f-4d51-4d16-b797-2dfe110f30bd.png" width="250px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/4240a69f-4d51-4d16-b797-2dfe110f30bd.png" width="250px"> </div><br>
## 解题思路
@ -22,3 +22,10 @@ public int[] multiply(int[] A) {
return B;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -35,3 +35,10 @@ public int StrToInt(String str) {
return isNegative ? -ret : ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -8,7 +8,7 @@
二叉查找树中两个节点 p, q 的公共祖先 root 满足 root.val >= p.val && root.val <= q.val
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/047faac4-a368-4565-8331-2b66253080d3.jpg" width="220"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/047faac4-a368-4565-8331-2b66253080d3.jpg" width="220"/> </div><br>
```java
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
@ -28,7 +28,7 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
在左右子树中查找是否存在 p 或者 q如果 p q 分别在两个子树中那么就说明根节点就是最低公共祖先
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d27c99f0-7881-4f2d-9675-c75cbdee3acd.jpg" width="250"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/d27c99f0-7881-4f2d-9675-c75cbdee3acd.jpg" width="250"/> </div><br>
```java
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
@ -39,3 +39,10 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return left == null ? right : right == null ? left : root;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -7,13 +7,13 @@
根据二叉树的前序遍历和中序遍历的结果重建出该二叉树假设输入的前序遍历和中序遍历的结果中都不含重复的数字
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/31d9adce-2af8-4754-8386-0aabb4e500b0.png" width="300"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/31d9adce-2af8-4754-8386-0aabb4e500b0.png" width="300"/> </div><br>
## 解题思路
前序遍历的第一个值为根节点的值使用这个值将中序遍历结果分成两部分左部分为树的左子树中序遍历结果右部分为树的右子树中序遍历的结果
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c269e362-1128-4212-9cf3-d4c12b363b2f.gif" width="330px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c269e362-1128-4212-9cf3-d4c12b363b2f.gif" width="330px"> </div><br>
```java
// 缓存中序遍历数组每个值对应的索引
@ -36,3 +36,10 @@ private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL) {
return root;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -24,11 +24,11 @@ public class TreeLinkNode {
如果一个节点的右子树不为空那么该节点的下一个节点是右子树的最左节点
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/b0611f89-1e5f-4494-a795-3544bf65042a.gif" width="220px"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/b0611f89-1e5f-4494-a795-3544bf65042a.gif" width="220px"/> </div><br>
否则向上找第一个左链接指向的树包含该节点的祖先节点
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/95080fae-de40-463d-a76e-783a0c677fec.gif" width="200px"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/95080fae-de40-463d-a76e-783a0c677fec.gif" width="200px"/> </div><br>
```java
public TreeLinkNode GetNext(TreeLinkNode pNode) {
@ -48,3 +48,10 @@ public TreeLinkNode GetNext(TreeLinkNode pNode) {
return null;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -10,7 +10,7 @@
in 栈用来处理入栈push操作out 栈用来处理出栈pop操作一个元素进入 in 栈之后出栈的顺序被反转当元素要出栈时需要先进入 out 此时元素出栈顺序再一次被反转因此出栈顺序就和最开始入栈顺序是相同的先进入的元素先退出这就是队列的顺序
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/3ea280b5-be7d-471b-ac76-ff020384357c.gif" width="350"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/3ea280b5-be7d-471b-ac76-ff020384357c.gif" width="350"/> </div><br>
```java
Stack<Integer> in = new Stack<Integer>();
@ -31,3 +31,10 @@ public int pop() throws Exception {
return out.pop();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,12 @@
[TOC]
<!-- GFM-TOC -->
* [解决的问题](#一解决的问题)
* [与虚拟机的比较](#二与虚拟机的比较)
* [优势](#三优势)
* [使用场景](#四使用场景)
* [镜像与容器](#五镜像与容器)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 解决的问题
@ -6,13 +14,13 @@
Docker 主要解决环境配置问题它是一种虚拟化技术对进程进行隔离被隔离的进程独立于宿主操作系统和其它隔离的进程使用 Docker 可以不修改应用程序代码不需要开发人员学习特定环境下的技术就能够将现有的应用程序部署在其它机器上
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/> </div><br>
# 与虚拟机的比较
虚拟机也是一种虚拟化技术它与 Docker 最大的区别在于它是通过模拟硬件并在硬件上安装操作系统来实现
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/be608a77-7b7f-4f8e-87cc-f2237270bf69.png" width="500"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/be608a77-7b7f-4f8e-87cc-f2237270bf69.png" width="500"/> </div><br>
## 启动速度
@ -66,7 +74,7 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
构建容器时通过在镜像的基础上添加一个可写层writable layer用来保存着容器运行过程中的修改
![](pics/docker-filesystems-busyboxrw.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/docker-filesystems-busyboxrw.png"/> </div><br>
# 参考资料
@ -79,3 +87,10 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
- [What is Docker](https://www.docker.com/what-docker)
- [持续集成是什么](http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,10 +1,24 @@
[TOC]
<!-- GFM-TOC -->
* [集中式与分布式](#集中式与分布式)
* [中心服务器](#中心服务器)
* [工作流](#工作流)
* [分支实现](#分支实现)
* [冲突](#冲突)
* [Fast forward](#fast-forward)
* [分支管理策略](#分支管理策略)
* [储藏Stashing](#储藏stashing)
* [SSH 传输设置](#ssh-传输设置)
* [.gitignore 文件](#gitignore-文件)
* [Git 命令一览](#git-命令一览)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 集中式与分布式
Git 属于分布式版本控制系统 SVN 属于集中式
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1fe2dc77-9a2d-4643-90b3-bbf50f649bac.png" width="600px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1fe2dc77-9a2d-4643-90b3-bbf50f649bac.png" width="600px"> </div><br>
集中式版本控制只有中心服务器拥有一份代码而分布式版本控制每个人的电脑上就有一份完整的代码
@ -26,45 +40,45 @@ Github 就是一个中心服务器。
Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库History 存储所有分支信息使用一个 HEAD 指针指向当前分支
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/71b97a50-a49f-4f1a-81d1-48c3364d61b3.png" width="700px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/71b97a50-a49f-4f1a-81d1-48c3364d61b3.png" width="700px"> </div><br>
- git add files 把文件的修改添加到暂存区
- git commit 把暂存区的修改提交到当前分支提交之后暂存区就被清空了
- git reset -- files 使用当前分支上的修改覆盖暂存区用来撤销最后一次 git add files
- git checkout -- files 使用暂存区的修改覆盖工作目录用来撤销本地修改
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/72ee7e9a-194d-42e9-b4d7-29c23417ca18.png" width="320px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/72ee7e9a-194d-42e9-b4d7-29c23417ca18.png" width="320px"> </div><br>
可以跳过暂存区域直接从分支中取出修改或者直接提交修改到分支中
- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
- git checkout HEAD -- files 取出最后一次修改可以用来进行回滚操作
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a4a0a6e6-386b-4bfa-b899-ec33d3310f3e.png" width="500px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a4a0a6e6-386b-4bfa-b899-ec33d3310f3e.png" width="500px"> </div><br>
# 分支实现
使用指针将每个提交连接成一条时间线HEAD 指针指向当前分支指针
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ec4d7464-7140-46d8-827e-d63634202e1e.png" width="220px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ec4d7464-7140-46d8-827e-d63634202e1e.png" width="220px"> </div><br>
新建分支是新建一个指针指向时间线的最后一个节点并让 HEAD 指针指向新分支表示新分支成为当前分支
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/66d00642-ce37-466c-8f7a-143d0bf84cd6.png" width="220px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/66d00642-ce37-466c-8f7a-143d0bf84cd6.png" width="220px"> </div><br>
每次提交只会让当前分支指针向前移动而其它分支指针不会移动
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/72a01242-e6b4-46c5-a285-24e754d63093.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/72a01242-e6b4-46c5-a285-24e754d63093.png" width="300px"> </div><br>
合并分支也只需要改变指针即可
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/94617147-0cbd-4a28-847d-81e52efb1b1e.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/94617147-0cbd-4a28-847d-81e52efb1b1e.png" width="300px"> </div><br>
# 冲突
当两个分支都对同一个文件的同一行进行了修改在分支合并时就会产生冲突
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/32b05e81-41b3-414a-8656-736c9604e3d6.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/32b05e81-41b3-414a-8656-736c9604e3d6.png" width="300px"> </div><br>
Git 会使用 <<<<<<< ======= >>>>>>> 标记出不同分支的内容只需要把不同分支中冲突部分修改成一样就能解决冲突
@ -86,7 +100,7 @@ Creating a new branch is quick AND simple.
$ git merge --no-ff -m "merge with no-ff" dev
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9a519773-84b2-4c81-81cf-4e7dd739a97a.png" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9a519773-84b2-4c81-81cf-4e7dd739a97a.png" width="350px"> </div><br>
# 分支管理策略
@ -94,7 +108,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
日常开发在开发分支 dev 上进行
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg" width="">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg" width=""> </div><br>
# 储藏Stashing
@ -134,7 +148,7 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
# Git 命令一览
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7a29acce-f243-4914-9f00-f2988c528412.jpg" width="">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7a29acce-f243-4914-9f00-f2988c528412.jpg" width=""> </div><br>
比较详细的地址http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
@ -144,3 +158,10 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
- [图解 Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)
- [廖雪峰 : Git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
- [Learn Git Branching](https://learngitbranching.js.org/)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,60 @@
[TOC]
<!-- GFM-TOC -->
* [ 基础概念](#-基础概念)
* [URI](#uri)
* [请求和响应报文](#请求和响应报文)
* [HTTP 方法](#二http-方法)
* [GET](#get)
* [HEAD](#head)
* [POST](#post)
* [PUT](#put)
* [PATCH](#patch)
* [DELETE](#delete)
* [OPTIONS](#options)
* [CONNECT](#connect)
* [TRACE](#trace)
* [HTTP 状态码](#三http-状态码)
* [1XX 信息](#1xx-信息)
* [2XX 成功](#2xx-成功)
* [3XX 重定向](#3xx-重定向)
* [4XX 客户端错误](#4xx-客户端错误)
* [5XX 服务器错误](#5xx-服务器错误)
* [HTTP 首部](#四http-首部)
* [通用首部字段](#通用首部字段)
* [请求首部字段](#请求首部字段)
* [响应首部字段](#响应首部字段)
* [实体首部字段](#实体首部字段)
* [具体应用](#五具体应用)
* [连接管理](#连接管理)
* [Cookie](#cookie)
* [缓存](#缓存)
* [内容协商](#内容协商)
* [内容编码](#内容编码)
* [范围请求](#范围请求)
* [分块传输编码](#分块传输编码)
* [多部分对象集合](#多部分对象集合)
* [虚拟主机](#虚拟主机)
* [通信数据转发](#通信数据转发)
* [HTTPS](#六https)
* [加密](#加密)
* [认证](#认证)
* [完整性保护](#完整性保护)
* [HTTPS 的缺点](#https-的缺点)
* [HTTP/2.0](#七http20)
* [HTTP/1.x 缺陷](#http1x-缺陷)
* [二进制分帧层](#二进制分帧层)
* [服务端推送](#服务端推送)
* [首部压缩](#首部压缩)
* [HTTP/1.1 新特性](#八http11-新特性)
* [GET POST 比较](#九get--post-比较)
* [作用](#作用)
* [参数](#参数)
* [安全](#安全)
* [幂等性](#幂等性)
* [可缓存](#可缓存)
* [XMLHttpRequest](#xmlhttprequest)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 基础概念
@ -6,21 +62,21 @@
URI 包含 URL URN
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8441b2c4-dca7-4d6b-8efb-f22efccaf331.png" width="500px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8441b2c4-dca7-4d6b-8efb-f22efccaf331.png" width="500px"> </div><br>
## 请求和响应报文
### 1. 请求报文
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/HTTP_RequestMessageExample.png" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/HTTP_RequestMessageExample.png" width=""/> </div><br>
### 2. 响应报文
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/HTTP_ResponseMessageExample.png" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/HTTP_ResponseMessageExample.png" width=""/> </div><br>
# HTTP 方法
客户端发送的 **请求报文** 第一行为请求行包含了方法字段
客户端发送的 **请求报文** 第一行为请求行包含了方法字段
## GET
@ -103,7 +159,7 @@ DELETE /file.html HTTP/1.1
CONNECT www.example.com:443 HTTP/1.1
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
## TRACE
@ -117,7 +173,7 @@ CONNECT www.example.com:443 HTTP/1.1
# HTTP 状态码
服务器返回的 **响应报文** 中第一行为状态行包含了状态码以及原因短语用来告知客户端请求的结果
服务器返回的 **响应报文** 中第一行为状态行包含了状态码以及原因短语用来告知客户端请求的结果
| 状态码 | 类别 | 含义 |
| :---: | :---: | :---: |
@ -129,45 +185,45 @@ CONNECT www.example.com:443 HTTP/1.1
## 1XX 信息
- **100 Continue** 表明到目前为止都很正常客户端可以继续发送请求或者忽略这个响应
- **100 Continue** 表明到目前为止都很正常客户端可以继续发送请求或者忽略这个响应
## 2XX 成功
- **200 OK**
- **200 OK**
- **204 No Content** 请求已经成功处理但是返回的响应报文不包含实体的主体部分一般在只需要从客户端往服务器发送信息而不需要返回数据时使用
- **204 No Content** 请求已经成功处理但是返回的响应报文不包含实体的主体部分一般在只需要从客户端往服务器发送信息而不需要返回数据时使用
- **206 Partial Content** 表示客户端进行了范围请求响应报文包含由 Content-Range 指定范围的实体内容
- **206 Partial Content** 表示客户端进行了范围请求响应报文包含由 Content-Range 指定范围的实体内容
## 3XX 重定向
- **301 Moved Permanently** 永久性重定向
- **301 Moved Permanently** 永久性重定向
- **302 Found** 临时性重定向
- **302 Found** 临时性重定向
- **303 See Other** 302 有着相同的功能但是 303 明确要求客户端应该采用 GET 方法获取资源
- **303 See Other** 302 有着相同的功能但是 303 明确要求客户端应该采用 GET 方法获取资源
- 虽然 HTTP 协议规定 301302 状态下重定向时不允许把 POST 方法改成 GET 方法但是大多数浏览器都会在 301302 303 状态下的重定向把 POST 方法改成 GET 方法
- **304 Not Modified** 如果请求报文首部包含一些条件例如If-MatchIf-Modified-SinceIf-None-MatchIf-RangeIf-Unmodified-Since如果不满足条件则服务器会返回 304 状态码
- **304 Not Modified** 如果请求报文首部包含一些条件例如If-MatchIf-Modified-SinceIf-None-MatchIf-RangeIf-Unmodified-Since如果不满足条件则服务器会返回 304 状态码
- **307 Temporary Redirect** 临时重定向 302 的含义类似但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法
- **307 Temporary Redirect** 临时重定向 302 的含义类似但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法
## 4XX 客户端错误
- **400 Bad Request** 请求报文中存在语法错误
- **400 Bad Request** 请求报文中存在语法错误
- **401 Unauthorized** 该状态码表示发送的请求需要有认证信息BASIC 认证DIGEST 认证如果之前已进行过一次请求则表示用户认证失败
- **401 Unauthorized** 该状态码表示发送的请求需要有认证信息BASIC 认证DIGEST 认证如果之前已进行过一次请求则表示用户认证失败
- **403 Forbidden** 请求被拒绝
- **403 Forbidden** 请求被拒绝
- **404 Not Found**
- **404 Not Found**
## 5XX 服务器错误
- **500 Internal Server Error** 服务器正在执行请求时发生错误
- **500 Internal Server Error** 服务器正在执行请求时发生错误
- **503 Service Unavailable** 服务器暂时处于超负载或正在进行停机维护现在无法处理请求
- **503 Service Unavailable** 服务器暂时处于超负载或正在进行停机维护现在无法处理请求
# HTTP 首部
@ -246,7 +302,7 @@ CONNECT www.example.com:443 HTTP/1.1
## 连接管理
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/HTTP1_x_Connections.png" width="800"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/HTTP1_x_Connections.png" width="800"/> </div><br>
### 1. 短连接与长连接
@ -380,7 +436,7 @@ Session 可以存储在服务器上的文件、数据库或者内存中。也可
HTTP/1.1 通过 Cache-Control 首部字段来控制缓存
**3.1 禁止进行缓存**
**3.1 禁止进行缓存**
no-store 指令规定不能对请求或响应的任何一部分进行缓存
@ -388,7 +444,7 @@ no-store 指令规定不能对请求或响应的任何一部分进行缓存。
Cache-Control: no-store
```
**3.2 强制确认缓存**
**3.2 强制确认缓存**
no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性只有当缓存资源有效时才能使用该缓存对客户端的请求进行响应
@ -396,7 +452,7 @@ no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源
Cache-Control: no-cache
```
**3.3 私有缓存和公共缓存**
**3.3 私有缓存和公共缓存**
private 指令规定了将资源作为私有缓存只能被单独用户使用一般存储在用户浏览器中
@ -410,7 +466,7 @@ public 指令规定了将资源作为公共缓存,可以被多个用户使用
Cache-Control: public
```
**3.4 缓存过期机制**
**3.4 缓存过期机制**
max-age 指令出现在请求报文并且缓存资源的缓存时间小于该指令指定的时间那么就能接受该缓存
@ -459,7 +515,7 @@ If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
### 1. 类型
**1.1 服务端驱动型**
**1.1 服务端驱动型**
客户端设置特定的 HTTP 首部字段例如 AcceptAccept-CharsetAccept-EncodingAccept-Language服务器根据这些字段返回特定的资源
@ -469,7 +525,7 @@ If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
- 客户端提供的信息相当冗长HTTP/2 协议的首部压缩机制缓解了这个问题并且存在隐私风险HTTP 指纹识别技术
- 给定的资源需要返回不同的展现形式共享缓存的效率会降低而服务器端的实现会越来越复杂
**1.2 代理驱动型**
**1.2 代理驱动型**
服务器返回 300 Multiple Choices 或者 406 Not Acceptable客户端从中选出最合适的那个资源
@ -575,11 +631,11 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
- 用户察觉得到正向代理的存在
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
- 而反向代理一般位于内部网络中用户察觉不到
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2d09a847-b854-439c-9198-b29c65810944.png" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
### 2. 网关
@ -601,7 +657,7 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
通过使用 SSLHTTPS 具有了加密防窃听认证防伪装和完整性保护防篡改
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ssl-offloading.jpg" width="700"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ssl-offloading.jpg" width="700"/> </div><br>
## 加密
@ -612,7 +668,7 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点运算速度快
- 缺点无法安全地将密钥传输给通信方
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
### 2.非对称密钥加密
@ -625,17 +681,17 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSLSecure Sockets Layer
- 优点可以更安全地将公开密钥传输给通信发送方
- 缺点运算速度慢
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
### 3. HTTPS 采用的加密方式
HTTPS 采用混合的加密机制使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性之后使用对称密钥加密进行通信来保证通信过程的效率下图中的 Session Key 就是对称密钥
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/How-HTTPS-Works.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/How-HTTPS-Works.png" width="600"/> </div><br>
## 认证
通过使用 **证书** 来对通信方进行认证
通过使用 **证书** 来对通信方进行认证
数字证书认证机构CACertificate Authority是客户端与服务器双方都可信赖的第三方机构
@ -643,7 +699,7 @@ HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对
进行 HTTPS 通信时服务器会把证书发送给客户端客户端取得其中的公开密钥之后先使用数字签名进行验证如果验证通过就可以开始通信了
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2017-06-11-ca.png" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2017-06-11-ca.png" width=""/> </div><br>
## 完整性保护
@ -672,7 +728,7 @@ HTTP/1.x 实现简单是以牺牲性能为代价的:
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 它们都是二进制格式的
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
在通信过程中只会有一个 TCP 连接存在它承载了任意数量的双向数据流Stream
@ -680,13 +736,13 @@ HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式
- 消息Message是与逻辑请求或响应对应的完整的一系列帧
- Frame是最小的通信单位来自不同数据流的帧可以交错发送然后再根据每个帧头的数据流标识符重新组装
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
## 服务端推送
HTTP/2.0 在客户端请求一个资源时会把相关的资源一起发送给客户端客户端就不需要再次发起请求了例如客户端请求 page.html 页面服务端就把 script.js style.css 等与之相关的资源一起发给客户端
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
## 首部压缩
@ -696,7 +752,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见
不仅如此HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/_u4E0B_u8F7D.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/_u4E0B_u8F7D.png" width="600"/> </div><br>
# HTTP/1.1 新特性
@ -821,3 +877,10 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404
- [Symmetric vs. Asymmetric Encryption What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences)
- [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2)
- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,35 @@
[TOC]
<!-- GFM-TOC -->
* [概览](#一概览)
* [磁盘操作](#二磁盘操作)
* [字节操作](#三字节操作)
* [实现文件复制](#实现文件复制)
* [装饰者模式](#装饰者模式)
* [字符操作](#四字符操作)
* [编码与解码](#编码与解码)
* [String 的编码方式](#string-的编码方式)
* [Reader Writer](#reader--writer)
* [实现逐行输出文本文件的内容](#实现逐行输出文本文件的内容)
* [对象操作](#五对象操作)
* [序列化](#序列化)
* [Serializable](#serializable)
* [transient](#transient)
* [网络操作](#六网络操作)
* [InetAddress](#inetaddress)
* [URL](#url)
* [Sockets](#sockets)
* [Datagram](#datagram)
* [NIO](#七nio)
* [流与块](#流与块)
* [通道与缓冲区](#通道与缓冲区)
* [缓冲区状态变量](#缓冲区状态变量)
* [文件 NIO 实例](#文件-nio-实例)
* [选择器](#选择器)
* [套接字 NIO 实例](#套接字-nio-实例)
* [内存映射文件](#内存映射文件)
* [对比](#对比)
* [参考资料](#八参考资料)
<!-- GFM-TOC -->
# 概览
@ -66,7 +97,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
- FileInputStream InputStream 的子类属于具体组件提供了字节流的输入操作
- FilterInputStream 属于抽象装饰者装饰者用于装饰组件为组件提供额外的功能例如 BufferedInputStream FileInputStream 提供缓存的功能
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9709694b-db05-4cce-8d2f-1c8b09f4d921.png" width="650px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9709694b-db05-4cce-8d2f-1c8b09f4d921.png" width="650px"> </div><br>
实例化一个具有缓存功能的字节流对象时只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可
@ -246,7 +277,7 @@ public static void main(String[] args) throws IOException {
- Socket客户端类
- 服务器和客户端通过 InputStream OutputStream 进行输入输出
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1e6affc4-18e5-4596-96ef-fb84c63bf88a.png" width="550px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1e6affc4-18e5-4596-96ef-fb84c63bf88a.png" width="550px"> </div><br>
## Datagram
@ -308,23 +339,23 @@ I/O 包和 NIO 已经很好地集成了java.io.\* 已经以 NIO 为基础重
新建一个大小为 8 个字节的缓冲区此时 position 0 limit = capacity = 8capacity 变量不会改变下面的讨论会忽略它
![](pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
从输入通道中读取 5 个字节数据写入缓冲区中此时 position 5limit 保持不变
![](pics/80804f52-8815-4096-b506-48eef3eed5c6.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
在将缓冲区的数据写到输出通道之前需要先调用 flip() 方法这个方法将 limit 设置为当前 position并将 position 设置为 0
![](pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
从缓冲区中取 4 个字节到输出缓冲中此时 position 设为 4
![](pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
最后需要调用 clear() 方法来清空缓冲区此时 position limit 都被设置为最初位置
![](pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
## 文件 NIO 实例
@ -382,7 +413,7 @@ NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用
应该注意的是只有套接字 Channel 才能配置为非阻塞 FileChannel 不能 FileChannel 配置非阻塞也没有意义
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/093f9e57-429c-413a-83ee-c689ba596cef.png" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/093f9e57-429c-413a-83ee-c689ba596cef.png" width="350px"> </div><br>
### 1. 创建选择器
@ -587,3 +618,10 @@ NIO 与普通 I/O 的区别主要有以下两点:
- [NIO 与传统 IO 的区别](http://blog.csdn.net/shimiso/article/details/24990499)
- [Decorator Design Pattern](http://stg-tud.github.io/sedc/Lecture/ws13-14/5.3-Decorator.html#mode=document)
- [Socket Multicast](http://labojava.blogspot.com/2012/12/socket-multicast.html)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,44 @@
[TOC]
<!-- GFM-TOC -->
* [数据类型](#一数据类型)
* [基本类型](#基本类型)
* [包装类型](#包装类型)
* [缓存池](#缓存池)
* [String](#二string)
* [概览](#概览)
* [不可变的好处](#不可变的好处)
* [String, StringBuffer and StringBuilder](#string,-stringbuffer-and-stringbuilder)
* [String Pool](#string-pool)
* [new String("abc")](#new-string"abc")
* [运算](#三运算)
* [参数传递](#参数传递)
* [float double](#float--double)
* [隐式类型转换](#隐式类型转换)
* [switch](#switch)
* [继承](#四继承)
* [访问权限](#访问权限)
* [抽象类与接口](#抽象类与接口)
* [super](#super)
* [重写与重载](#重写与重载)
* [Object 通用方法](#五object-通用方法)
* [概览](#概览)
* [equals()](#equals)
* [hashCode()](#hashcode)
* [toString()](#tostring)
* [clone()](#clone)
* [关键字](#六关键字)
* [final](#final)
* [static](#static)
* [反射](#七反射)
* [异常](#八异常)
* [泛型](#九泛型)
* [注解](#十注解)
* [十一特性](#十一特性)
* [Java 各版本的新特性](#java-各版本的新特性)
* [Java C++ 的区别](#java--c-的区别)
* [JRE or JDK](#jre-or-jdk)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 数据类型
@ -145,21 +185,21 @@ value 数组被声明为 final这意味着 value 数组初始化之后就不
## 不可变的好处
**1. 可以缓存 hash **
**1. 可以缓存 hash **
因为 String hash 值经常被使用例如 String 用做 HashMap key不可变的特性可以使得 hash 值也不可变因此只需要进行一次计算
**2. String Pool 的需要**
**2. String Pool 的需要**
如果一个 String 对象已经被创建过了那么就会从 String Pool 中取得引用只有 String 是不可变的才可能使用 String Pool
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9112288f-23f5-4e53-b222-a46fdbca1603.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9112288f-23f5-4e53-b222-a46fdbca1603.png" width="300px"> </div><br>
**3. 安全性**
**3. 安全性**
String 经常作为参数String 不可变性可以保证参数不可变例如在作为网络连接参数的情况下如果 String 是可变的那么在网络连接过程中String 被改变改变 String 对象的那一方以为现在连接的是其它主机而实际情况却不一定是
**4. 线程安全**
**4. 线程安全**
String 不可变性天生具备线程安全可以在多个线程中安全地使用
@ -167,12 +207,12 @@ String 不可变性天生具备线程安全,可以在多个线程中安全地
## String, StringBuffer and StringBuilder
**1. 可变性**
**1. 可变性**
- String 不可变
- StringBuffer StringBuilder 可变
**2. 线程安全**
**2. 线程安全**
- String 不可变因此是线程安全的
- StringBuilder 不是线程安全的
@ -469,7 +509,7 @@ public class AccessWithInnerClassExample {
## 抽象类与接口
**1. 抽象类**
**1. 抽象类**
抽象类和抽象方法都使用 abstract 关键字进行声明如果一个类中包含抽象方法那么这个类必须声明为抽象类
@ -504,7 +544,7 @@ AbstractClassExample ac2 = new AbstractExtendClassExample();
ac2.func1();
```
**2. 接口**
**2. 接口**
接口是抽象类的延伸 Java 8 之前它可以看成是一个完全抽象的类也就是说它不能有任何的方法实现
@ -548,14 +588,14 @@ ie2.func1();
System.out.println(InterfaceExample.x);
```
**3. 比较**
**3. 比较**
- 从设计层面上看抽象类提供了一种 IS-A 关系那么就必须满足里式替换原则即子类对象必须能够替换掉所有父类对象而接口更像是一种 LIKE-A 关系它只是提供一种方法实现契约并不要求接口和实现接口的类具有 IS-A 关系
- 从使用上来看一个类可以实现多个接口但是不能继承多个抽象类
- 接口的字段只能是 static final 类型的而抽象类的字段没有这种限制
- 接口的成员只能是 public 而抽象类的成员可以有多种访问权限
**4. 使用选择**
**4. 使用选择**
使用接口
@ -629,7 +669,7 @@ SuperExtendExample.func()
## 重写与重载
**1. 重写Override**
**1. 重写Override**
存在于继承体系中指子类实现了一个与父类在方法声明上完全相同的一个方法
@ -733,7 +773,7 @@ public static void main(String[] args) {
}
```
**2. 重载Overload**
**2. 重载Overload**
存在于同一个类中指一个方法与已经存在的方法名称上相同但是参数类型个数顺序至少有一个不同
@ -770,7 +810,7 @@ public final void wait() throws InterruptedException
## equals()
**1. 等价关系**
**1. 等价关系**
自反性
@ -807,7 +847,7 @@ x.equals(y) == x.equals(y); // true
x.equals(null); // false;
```
**2. 等价与相等**
**2. 等价与相等**
- 对于基本类型== 判断两个值是否相等基本类型没有 equals() 方法
- 对于引用类型== 判断两个变量是否引用同一个对象 equals() 判断引用的对象是否等价
@ -819,7 +859,7 @@ System.out.println(x.equals(y)); // true
System.out.println(x == y); // false
```
**3. 实现**
**3. 实现**
- 检查是否为同一个对象的引用如果是直接返回 true
- 检查是否是同一个类型如果不是直接返回 false
@ -912,7 +952,7 @@ ToStringExample@4554617c
## clone()
**1. cloneable**
**1. cloneable**
clone() Object protected 方法它不是 public一个类不显式去重写 clone()其它类就不能直接去调用该类实例的 clone() 方法
@ -971,7 +1011,7 @@ public class CloneExample implements Cloneable {
}
```
**2. 浅拷贝**
**2. 浅拷贝**
拷贝对象和原始对象的引用类型引用同一个对象
@ -1014,7 +1054,7 @@ e1.set(2, 222);
System.out.println(e2.get(2)); // 222
```
**3. 深拷贝**
**3. 深拷贝**
拷贝对象和原始对象的引用类型引用不同对象
@ -1062,7 +1102,7 @@ e1.set(2, 222);
System.out.println(e2.get(2)); // 2
```
**4. clone() 的替代方案**
**4. clone() 的替代方案**
使用 clone() 方法来拷贝一个对象即复杂又有风险它会抛出异常并且还需要类型转换Effective Java 书上讲到最好不要去使用 clone()可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象
@ -1106,7 +1146,7 @@ System.out.println(e2.get(2)); // 2
## final
**1. 数据**
**1. 数据**
声明数据为常量可以是编译时常量也可以是在运行时被初始化后不能被改变的常量
@ -1120,19 +1160,19 @@ final A y = new A();
y.a = 1;
```
**2. 方法**
**2. 方法**
声明方法不能被子类重写
private 方法隐式地被指定为 final如果在子类中定义的方法和基类中的一个 private 方法签名相同此时子类的方法不是重写基类方法而是在子类中定义了一个新的方法
**3. **
**3. **
声明类不允许被继承
## static
**1. 静态变量**
**1. 静态变量**
- 静态变量又称为类变量也就是说这个变量属于类的类所有的实例都共享静态变量可以直接通过类名来访问它静态变量在内存中只存在一份
- 实例变量每创建一个实例就会产生一个实例变量它与该实例同生共死
@ -1152,7 +1192,7 @@ public class A {
}
```
**2. 静态方法**
**2. 静态方法**
静态方法在类加载的时候就存在了它不依赖于任何实例所以静态方法必须有实现也就是说它不能是抽象方法
@ -1180,7 +1220,7 @@ public class A {
}
```
**3. 静态语句块**
**3. 静态语句块**
静态语句块在类初始化时运行一次
@ -1201,7 +1241,7 @@ public class A {
123
```
**4. 静态内部类**
**4. 静态内部类**
非静态内部类依赖于外部类的实例而静态内部类不需要
@ -1225,7 +1265,7 @@ public class OuterClass {
静态内部类不能访问外部类的非静态的变量和方法
**5. 静态导包**
**5. 静态导包**
在使用静态变量和方法时不用再指明 ClassName从而简化代码但可读性大大降低
@ -1233,7 +1273,7 @@ public class OuterClass {
import static com.xxx.ClassName.*
```
**6. 初始化顺序**
**6. 初始化顺序**
静态变量和静态语句块优先于实例变量和普通语句块静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序
@ -1277,7 +1317,7 @@ public InitialOrderTest() {
# 反射
每个类都有一个 **Class** 对象包含了与类有关的信息当编译一个新类时会产生一个同名的 .class 文件该文件内容保存着 Class 对象
每个类都有一个 **Class** 对象包含了与类有关的信息当编译一个新类时会产生一个同名的 .class 文件该文件内容保存着 Class 对象
类加载相当于 Class 对象的加载类在第一次使用时才动态加载到 JVM 也可以使用 `Class.forName("com.mysql.jdbc.Driver")` 这种方式来控制类的加载该方法会返回一个 Class 对象
@ -1285,25 +1325,25 @@ public InitialOrderTest() {
Class java.lang.reflect 一起对反射提供了支持java.lang.reflect 类库主要包含了以下三个类
- **Field** 可以使用 get() set() 方法读取和修改 Field 对象关联的字段
- **Method** 可以使用 invoke() 方法调用与 Method 对象关联的方法
- **Constructor** 可以用 Constructor newInstance() 创建新的对象
- **Field** 可以使用 get() set() 方法读取和修改 Field 对象关联的字段
- **Method** 可以使用 invoke() 方法调用与 Method 对象关联的方法
- **Constructor** 可以用 Constructor newInstance() 创建新的对象
**反射的优点**
**反射的优点**
* **可扩展性** 应用程序可以利用全限定名创建可扩展对象的实例来使用来自外部的用户自定义类
* **类浏览器和可视化开发环境** 一个类浏览器需要可以枚举类的成员可视化开发环境 IDE可以从利用反射中可用的类型信息中受益以帮助程序员编写正确的代码
* **调试器和测试工具** 调试器需要能够检查一个类里的私有成员测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义以确保一组测试中有较高的代码覆盖率
* **可扩展性** 应用程序可以利用全限定名创建可扩展对象的实例来使用来自外部的用户自定义类
* **类浏览器和可视化开发环境** 一个类浏览器需要可以枚举类的成员可视化开发环境 IDE可以从利用反射中可用的类型信息中受益以帮助程序员编写正确的代码
* **调试器和测试工具** 调试器需要能够检查一个类里的私有成员测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义以确保一组测试中有较高的代码覆盖率
**反射的缺点**
**反射的缺点**
尽管反射非常强大但也不能滥用如果一个功能可以不用反射完成那么最好就不用在我们使用反射技术时下面几条内容应该牢记于心
* **性能开销** 反射涉及了动态类型的解析所以 JVM 无法对这些代码进行优化因此反射操作的效率要比那些非反射操作低得多我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射
* **性能开销** 反射涉及了动态类型的解析所以 JVM 无法对这些代码进行优化因此反射操作的效率要比那些非反射操作低得多我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射
* **安全限制** 使用反射技术要求程序必须在一个没有安全限制的环境中运行如果一个程序必须在有安全限制的环境中运行 Applet那么这就是个问题了
* **安全限制** 使用反射技术要求程序必须在一个没有安全限制的环境中运行如果一个程序必须在有安全限制的环境中运行 Applet那么这就是个问题了
* **内部暴露** 由于反射允许代码执行一些在正常情况下不被允许的操作比如访问私有的属性和方法所以使用反射可能会导致意料之外的副作用这可能导致代码功能失调并破坏可移植性反射代码破坏了抽象性因此当平台发生改变的时候代码的行为就有可能也随着变化
* **内部暴露** 由于反射允许代码执行一些在正常情况下不被允许的操作比如访问私有的属性和方法所以使用反射可能会导致意料之外的副作用这可能导致代码功能失调并破坏可移植性反射代码破坏了抽象性因此当平台发生改变的时候代码的行为就有可能也随着变化
- [Trail: The Reflection API](https://docs.oracle.com/javase/tutorial/reflect/index.html)
@ -1311,12 +1351,12 @@ Class 和 java.lang.reflect 一起对反射提供了支持java.lang.reflect
# 异常
Throwable 可以用来表示任何可以作为异常抛出的类分为两种 **Error** **Exception**其中 Error 用来表示 JVM 无法处理的错误Exception 分为两种
Throwable 可以用来表示任何可以作为异常抛出的类分为两种 **Error** **Exception**其中 Error 用来表示 JVM 无法处理的错误Exception 分为两种
- **受检异常** 需要用 try...catch... 语句捕获并进行处理并且可以从异常中恢复
- **非受检异常** 是程序运行时错误例如除 0 会引发 Arithmetic Exception此时程序崩溃并且无法恢复
- **受检异常** 需要用 try...catch... 语句捕获并进行处理并且可以从异常中恢复
- **非受检异常** 是程序运行时错误例如除 0 会引发 Arithmetic Exception此时程序崩溃并且无法恢复
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/PPjwP.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/PPjwP.png" width="600"/> </div><br>
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
@ -1345,7 +1385,7 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译
## Java 各版本的新特性
**New highlights in Java SE 8**
**New highlights in Java SE 8**
1. Lambda Expressions
2. Pipelines and Streams
@ -1357,7 +1397,7 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译
8. Parallel operations
9. PermGen Error Removed
**New highlights in Java SE 7**
**New highlights in Java SE 7**
1. Strings in Switch Statement
2. Type Inference for Generic Instance Creation
@ -1392,3 +1432,10 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译
- Eckel B. Java 编程思想[M]. 机械工业出版社, 2002.
- Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,22 @@
[TOC]
<!-- GFM-TOC -->
* [概览](#一概览)
* [Collection](#collection)
* [Map](#map)
* [容器中的设计模式](#二容器中的设计模式)
* [迭代器模式](#迭代器模式)
* [适配器模式](#适配器模式)
* [源码分析](#三源码分析)
* [ArrayList](#arraylist)
* [Vector](#vector)
* [CopyOnWriteArrayList](#copyonwritearraylist)
* [LinkedList](#linkedlist)
* [HashMap](#hashmap)
* [ConcurrentHashMap](#concurrenthashmap)
* [LinkedHashMap](#linkedhashmap)
* [WeakHashMap](#weakhashmap)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 概览
@ -6,7 +24,7 @@
## Collection
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/73403d84-d921-49f1-93a9-d8fe050f3497.png" width="800px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/73403d84-d921-49f1-93a9-d8fe050f3497.png" width="800px"> </div><br>
### 1. Set
@ -32,7 +50,7 @@
## Map
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/774d756b-902a-41a3-a3fd-81ca3ef688dc.png" width="500px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/774d756b-902a-41a3-a3fd-81ca3ef688dc.png" width="500px"> </div><br>
- TreeMap基于红黑树实现
@ -47,7 +65,7 @@
## 迭代器模式
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/93fb1d38-83f9-464a-a733-67b2e6bfddda.png" width="600px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/93fb1d38-83f9-464a-a733-67b2e6bfddda.png" width="600px"> </div><br>
Collection 继承了 Iterable 接口其中的 iterator() 方法能够产生一个 Iterator 对象通过这个对象就可以迭代遍历 Collection 中的元素
@ -108,7 +126,7 @@ public class ArrayList<E> extends AbstractList<E>
private static final int DEFAULT_CAPACITY = 10;
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/52a7744f-5bce-4ff3-a6f0-8449334d9f3d.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/52a7744f-5bce-4ff3-a6f0-8449334d9f3d.png" width="400px"> </div><br>
### 2. 扩容
@ -412,7 +430,7 @@ transient Node<E> first;
transient Node<E> last;
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c8563120-cb00-4dd6-9213-9d9b337a7f7c.png" width="500px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c8563120-cb00-4dd6-9213-9d9b337a7f7c.png" width="500px"> </div><br>
### 2. ArrayList 的比较
@ -434,7 +452,7 @@ transient Entry[] table;
Entry 存储着键值对它包含了四个字段 next 字段我们可以看出 Entry 是一个链表即数组中的每个位置被当成一个桶一个桶存放一个链表HashMap 使用拉链法来解决冲突同一个链表中存放哈希值和散列桶取模运算结果相同的 Entry
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9420a703-1f9d-42ce-808e-bcb82b56483d.png" width="550px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9420a703-1f9d-42ce-808e-bcb82b56483d.png" width="550px"> </div><br>
```java
static class Entry<K,V> implements Map.Entry<K,V> {
@ -510,7 +528,7 @@ map.put("K3", "V3");
- 计算键值对所在的桶
- 在链表上顺序查找时间复杂度显然和链表的长度成正比
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e0870f80-b79e-4542-ae39-7420d4b0d8fe.png" width="550px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e0870f80-b79e-4542-ae39-7420d4b0d8fe.png" width="550px"> </div><br>
### 3. put 操作
@ -600,7 +618,7 @@ int hash = hash(key);
int i = indexFor(hash, table.length);
```
**4.1 计算 hash **
**4.1 计算 hash **
```java
final int hash(Object k) {
@ -625,7 +643,7 @@ public final int hashCode() {
}
```
**4.2 取模**
**4.2 取模**
x = 1<<4 x 2 4 次方它具有以下性质
@ -846,7 +864,7 @@ final Segment<K,V>[] segments;
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/db808eff-31d7-4229-a4ad-b8ae71870a3a.png" width="550px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/db808eff-31d7-4229-a4ad-b8ae71870a3a.png" width="550px"> </div><br>
### 2. size 操作
@ -1132,3 +1150,10 @@ public final class ConcurrentCache<K, V> {
- [Java 集合细节asList 的缺陷](http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html)
- [Java Collection Framework The LinkedList Class](http://javaconceptoftheday.com/java-collection-framework-linkedlist-class/)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,8 +1,67 @@
[TOC]
<!-- GFM-TOC -->
* [线程状态转换](#一线程状态转换)
* [新建New](#新建new)
* [可运行Runnable](#可运行runnable)
* [阻塞Blocked](#阻塞blocked)
* [无限期等待Waiting](#无限期等待waiting)
* [限期等待Timed Waiting](#限期等待timed-waiting)
* [死亡Terminated](#死亡terminated)
* [使用线程](#二使用线程)
* [实现 Runnable 接口](#实现-runnable-接口)
* [实现 Callable 接口](#实现-callable-接口)
* [继承 Thread ](#继承-thread-)
* [实现接口 VS 继承 Thread](#实现接口-vs-继承-thread)
* [基础线程机制](#三基础线程机制)
* [Executor](#executor)
* [Daemon](#daemon)
* [sleep()](#sleep)
* [yield()](#yield)
* [中断](#四中断)
* [InterruptedException](#interruptedexception)
* [interrupted()](#interrupted)
* [Executor 的中断操作](#executor-的中断操作)
* [互斥同步](#五互斥同步)
* [synchronized](#synchronized)
* [ReentrantLock](#reentrantlock)
* [比较](#比较)
* [使用选择](#使用选择)
* [线程之间的协作](#六线程之间的协作)
* [join()](#join)
* [wait() notify() notifyAll()](#wait-notify-notifyall)
* [await() signal() signalAll()](#await-signal-signalall)
* [J.U.C - AQS](#七juc---aqs)
* [CountDownLatch](#countdownlatch)
* [CyclicBarrier](#cyclicbarrier)
* [Semaphore](#semaphore)
* [J.U.C - 其它组件](#八juc---其它组件)
* [FutureTask](#futuretask)
* [BlockingQueue](#blockingqueue)
* [ForkJoin](#forkjoin)
* [线程不安全示例](#九线程不安全示例)
* [Java 内存模型](#十java-内存模型)
* [主内存与工作内存](#主内存与工作内存)
* [内存间交互操作](#内存间交互操作)
* [内存模型三大特性](#内存模型三大特性)
* [先行发生原则](#先行发生原则)
* [十一线程安全](#十一线程安全)
* [不可变](#不可变)
* [互斥同步](#互斥同步)
* [非阻塞同步](#非阻塞同步)
* [无同步方案](#无同步方案)
* [十二锁优化](#十二锁优化)
* [自旋锁](#自旋锁)
* [锁消除](#锁消除)
* [锁粗化](#锁粗化)
* [轻量级锁](#轻量级锁)
* [偏向锁](#偏向锁)
* [十三多线程开发良好的实践](#十三多线程开发良好的实践)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 线程状态转换
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/adfb427d-3b21-40d7-a142-757f4ed73079.png" width="600px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/adfb427d-3b21-40d7-a142-757f4ed73079.png" width="600px"> </div><br>
## 新建New
@ -325,7 +384,7 @@ Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问
## synchronized
**1. 同步一个代码块**
**1. 同步一个代码块**
```java
public void func() {
@ -382,7 +441,7 @@ public static void main(String[] args) {
```
**2. 同步一个方法**
**2. 同步一个方法**
```java
public synchronized void func () {
@ -392,7 +451,7 @@ public synchronized void func () {
它和同步代码块一样作用于同一个对象
**3. 同步一个类**
**3. 同步一个类**
```java
public void func() {
@ -431,7 +490,7 @@ public static void main(String[] args) {
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
```
**4. 同步一个静态方法**
**4. 同步一个静态方法**
```java
public synchronized static void fun() {
@ -479,27 +538,27 @@ public static void main(String[] args) {
## 比较
**1. 锁的实现**
**1. 锁的实现**
synchronized JVM 实现的 ReentrantLock JDK 实现的
**2. 性能**
**2. 性能**
新版本 Java synchronized 进行了很多优化例如自旋锁等synchronized ReentrantLock 大致相同
**3. 等待可中断**
**3. 等待可中断**
当持有锁的线程长期不释放锁的时候正在等待的线程可以选择放弃等待改为处理其他事情
ReentrantLock 可中断 synchronized 不行
**4. 公平锁**
**4. 公平锁**
公平锁是指多个线程在等待同一个锁时必须按照申请锁的时间顺序来依次获得锁
synchronized 中的锁是非公平的ReentrantLock 默认情况下也是非公平的但是也可以是公平的
**5. 锁绑定多个条件**
**5. 锁绑定多个条件**
一个 ReentrantLock 可以同时绑定多个 Condition 对象
@ -610,7 +669,7 @@ before
after
```
**wait() sleep() 的区别**
**wait() sleep() 的区别**
- wait() Object 的方法 sleep() Thread 的静态方法
- wait() 会释放锁sleep() 不会
@ -677,7 +736,7 @@ java.util.concurrentJ.U.C大大提高了并发性能AQS 被认为是 J.
维护了一个计数器 cnt每次调用 countDown() 方法会让计数器的值减 1减到 0 的时候那些因为调用 await() 方法而在等待的线程就会被唤醒
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ba078291-791e-4378-b6d1-ece76c2f0b14.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ba078291-791e-4378-b6d1-ece76c2f0b14.png" width="300px"> </div><br>
```java
public class CountdownLatchExample {
@ -726,7 +785,7 @@ public CyclicBarrier(int parties) {
}
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f71af66b-0d54-4399-a44b-f47b58321984.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f71af66b-0d54-4399-a44b-f47b58321984.png" width="300px"> </div><br>
```java
public class CyclicBarrierExample {
@ -848,12 +907,12 @@ other task is running...
java.util.concurrent.BlockingQueue 接口有以下阻塞队列的实现
- **FIFO 队列** LinkedBlockingQueueArrayBlockingQueue固定长度
- **优先级队列** PriorityBlockingQueue
- **FIFO 队列** LinkedBlockingQueueArrayBlockingQueue固定长度
- **优先级队列** PriorityBlockingQueue
提供了阻塞的 take() put() 方法如果队列为空 take() 将阻塞直到队列中有内容如果队列为满 put() 将阻塞直到队列有空闲位置
**使用 BlockingQueue 实现生产者消费者问题**
**使用 BlockingQueue 实现生产者消费者问题**
```java
public class ProducerConsumer {
@ -963,7 +1022,7 @@ public class ForkJoinPool extends AbstractExecutorService
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率每个线程都维护了一个双端队列用来存储需要执行的任务工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行窃取的任务必须是最晚的任务避免和队列所属线程发生竞争例如下图中Thread2 Thread1 的队列中拿出最晚的 Task1 任务Thread1 会拿出 Task2 来执行这样就避免发生竞争但是如果队列中只有一个任务时还是会发生竞争
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e42f188f-f4a9-4e6f-88fc-45f4682072fb.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e42f188f-f4a9-4e6f-88fc-45f4682072fb.png" width="300px"> </div><br>
# 线程不安全示例
@ -1018,19 +1077,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
加入高速缓存带来了一个新的问题缓存一致性如果多个缓存共享同一块主内存区域那么多个缓存的数据可能会不一致需要一些协议来解决这个问题
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/942ca0d2-9d5c-45a4-89cb-5fd89b61913f.png" width="600px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/942ca0d2-9d5c-45a4-89cb-5fd89b61913f.png" width="600px"> </div><br>
所有的变量都存储在主内存中每个线程还有自己的工作内存工作内存存储在高速缓存或者寄存器中保存了该线程使用的变量的主内存副本拷贝
线程只能直接操作工作内存中的变量不同线程之间的变量值传递需要通过主内存来完成
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/15851555-5abc-497d-ad34-efed10f43a6b.png" width="600px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/15851555-5abc-497d-ad34-efed10f43a6b.png" width="600px"> </div><br>
## 内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8b7ebbad-9604-4375-84e3-f412099d170c.png" width="450px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8b7ebbad-9604-4375-84e3-f412099d170c.png" width="450px"> </div><br>
- read把一个变量的值从主内存传输到工作内存中
- load read 之后执行 read 得到的值放入工作内存的变量副本中
@ -1053,11 +1112,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
下图演示了两个线程同时对 cnt 进行操作loadassignstore 这一系列操作整体上看不具备原子性那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存T2 依然可以读入旧值可以看出这两个线程虽然执行了两次自增运算但是主内存中 cnt 的值最后为 1 而不是 2因此对 int 类型读写操作满足原子性只是说明 loadassignstore 这些单个操作具备原子性
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2797a609-68db-4d7b-8701-41ac9a34b14f.jpg" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2797a609-68db-4d7b-8701-41ac9a34b14f.jpg" width="300px"> </div><br>
AtomicInteger 能保证多个线程修改的原子性
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dd563037-fcaa-4bd8-83b6-b39d93a12c77.jpg" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dd563037-fcaa-4bd8-83b6-b39d93a12c77.jpg" width="300px"> </div><br>
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现
@ -1165,7 +1224,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
在一个线程内在程序前面的操作先行发生于后面的操作
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/874b3ff7-7c5c-4e7a-b8ab-a82a3e038d20.png" width="180px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/874b3ff7-7c5c-4e7a-b8ab-a82a3e038d20.png" width="180px"> </div><br>
### 2. 管程锁定规则
@ -1173,7 +1232,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8996a537-7c4a-4ec8-a3b7-7ef1798eae26.png" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8996a537-7c4a-4ec8-a3b7-7ef1798eae26.png" width="350px"> </div><br>
### 3. volatile 变量规则
@ -1181,7 +1240,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/942f33c9-8ad9-4987-836f-007de4c21de0.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/942f33c9-8ad9-4987-836f-007de4c21de0.png" width="400px"> </div><br>
### 4. 线程启动规则
@ -1189,7 +1248,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6270c216-7ec0-4db7-94de-0003bce37cd2.png" width="380px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6270c216-7ec0-4db7-94de-0003bce37cd2.png" width="380px"> </div><br>
### 5. 线程加入规则
@ -1197,7 +1256,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
Thread 对象的结束先行发生于 join() 方法返回
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/233f8d89-31d7-413f-9c02-042f19c46ba1.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/233f8d89-31d7-413f-9c02-042f19c46ba1.png" width="400px"> </div><br>
### 6. 线程中断规则
@ -1415,7 +1474,7 @@ public class ThreadLocalExample1 {
它所对应的底层结构图为
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6782674c-1bfe-4879-af39-e9d722a95d39.png" width="500px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6782674c-1bfe-4879-af39-e9d722a95d39.png" width="500px"> </div><br>
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象
@ -1518,17 +1577,17 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
以下是 HotSpot 虚拟机对象头的内存布局这些数据被称为 Mark Word其中 tag bits 对应了五个状态这些状态在右侧的 state 表格中给出除了 marked for gc 状态其它四个状态已经在前面介绍过了
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
下图左侧是一个线程的虚拟机栈其中有一部分称为 Lock Record 的区域这是在轻量级锁运行过程创建的用于存放锁对象的 Mark Word而右侧就是一个锁对象包含了 Mark Word 和其它信息
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
轻量级锁是相对于传统的重量级锁而言它使用 CAS 操作来避免重量级锁使用互斥量的开销对于绝大部分的锁在整个同步周期内都是不存在竞争的因此也就不需要都使用互斥量进行同步可以先采用 CAS 操作进行同步如果 CAS 失败了再改用互斥量进行同步
当尝试获取一个锁对象时如果锁对象标记为 0 01说明锁对象的锁未锁定unlocked状态此时虚拟机在当前线程的虚拟机栈中创建 Lock Record然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针如果 CAS 操作成功了那么线程就获取了该对象上的锁并且对象的 Mark Word 的锁标记变为 00表示该对象处于轻量级锁状态
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
如果 CAS 操作失败了虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈如果是的话说明当前线程已经拥有了这个锁对象那就可以直接进入同步块继续执行否则说明这个锁对象已经被其他线程线程抢占了如果有两条以上的线程争用同一个锁那轻量级锁就不再有效要膨胀为重量级锁
@ -1540,7 +1599,7 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
当有另外一个线程去尝试获取这个锁对象时偏向状态就宣告结束此时撤销偏向Revoke Bias后恢复到未锁定状态或者轻量级锁状态
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
# 十三多线程开发良好的实践
@ -1575,3 +1634,10 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
- [JAVA FORK JOIN EXAMPLE](http://www.javacreed.com/java-fork-join-example/ "Java Fork Join Example")
- [聊聊并发Fork/Join 框架介绍](http://ifeve.com/talk-concurrency-forkjoin/)
- [Eliminating SynchronizationRelated Atomic Operations with Biased Locking and Bulk Rebiasing](http://www.oracle.com/technetwork/java/javase/tech/biasedlocking-oopsla2006-preso-150106.pdf)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,10 +1,38 @@
[TOC]
<!-- GFM-TOC -->
* [运行时数据区域](#一运行时数据区域)
* [程序计数器](#程序计数器)
* [Java 虚拟机栈](#java-虚拟机栈)
* [本地方法栈](#本地方法栈)
* [](#)
* [方法区](#方法区)
* [运行时常量池](#运行时常量池)
* [直接内存](#直接内存)
* [垃圾收集](#二垃圾收集)
* [判断一个对象是否可被回收](#判断一个对象是否可被回收)
* [引用类型](#引用类型)
* [垃圾收集算法](#垃圾收集算法)
* [垃圾收集器](#垃圾收集器)
* [内存分配与回收策略](#三内存分配与回收策略)
* [Minor GC Full GC](#minor-gc--full-gc)
* [内存分配策略](#内存分配策略)
* [Full GC 的触发条件](#full-gc-的触发条件)
* [类加载机制](#四类加载机制)
* [类的生命周期](#类的生命周期)
* [类加载过程](#类加载过程)
* [类初始化时机](#类初始化时机)
* [类与类加载器](#类与类加载器)
* [类加载器分类](#类加载器分类)
* [双亲委派模型](#双亲委派模型)
* [自定义类加载器实现](#自定义类加载器实现)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
本文大部分内容参考 **周志明深入理解 Java 虚拟机** 想要深入学习的话请看原书
本文大部分内容参考 **周志明深入理解 Java 虚拟机** 想要深入学习的话请看原书
# 运行时数据区域
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5778d113-8e13-4c53-b5bf-801e58080b97.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5778d113-8e13-4c53-b5bf-801e58080b97.png" width="400px"> </div><br>
## 程序计数器
@ -14,7 +42,7 @@
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表操作数栈常量池引用等信息从方法调用直至执行完成的过程对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8442519f-0b4d-48f4-8229-56f984363c69.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8442519f-0b4d-48f4-8229-56f984363c69.png" width="400px"> </div><br>
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小 JDK 1.4 中默认为 256K而在 JDK 1.5+ 默认为 1M
@ -33,7 +61,7 @@ java -Xss2M HackTheJava
本地方法一般是用其它语言CC++ 或汇编语言等编写的并且被编译为基于本机硬件和操作系统的程序对待这些方法需要特别处理
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/66a6899d-c6b0-4a47-8569-9d08f0baf86c.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/66a6899d-c6b0-4a47-8569-9d08f0baf86c.png" width="300px"> </div><br>
##
@ -118,7 +146,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收GC Roots 一般
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/83d909d2-3858-4fe1-8ff4-16471db0b180.png" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/83d909d2-3858-4fe1-8ff4-16471db0b180.png" width="350px"> </div><br>
### 3. 方法区的回收
@ -199,7 +227,7 @@ obj = null;
### 1. 标记 - 清除
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/005b481b-502b-4e3f-985d-d043c2b330aa.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/005b481b-502b-4e3f-985d-d043c2b330aa.png" width="400px"> </div><br>
在标记阶段程序会检查每个对象是否为活动对象如果是活动对象则程序会在对象头部打上标记
@ -214,7 +242,7 @@ obj = null;
### 2. 标记 - 整理
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ccd773a5-ad38-4022-895c-7ac318f31437.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ccd773a5-ad38-4022-895c-7ac318f31437.png" width="400px"> </div><br>
让所有存活的对象都向一端移动然后直接清理掉端边界以外的内存
@ -228,7 +256,7 @@ obj = null;
### 3. 复制
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/b2b77b9e-958c-4016-8ae5-9c6edd83871e.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/b2b77b9e-958c-4016-8ae5-9c6edd83871e.png" width="400px"> </div><br>
将内存划分为大小相等的两块每次只使用其中一块当这一块内存用完了就将还存活的对象复制到另一块上面然后再把使用过的内存空间进行一次清理
@ -249,7 +277,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1保证了内
## 垃圾收集器
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
以上是 HotSpot 虚拟机中的 7 个垃圾收集器连线表示垃圾收集器可以配合使用
@ -258,7 +286,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1保证了内
### 1. Serial 收集器
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
Serial 翻译为串行也就是说它以串行的方式执行
@ -270,7 +298,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 2. ParNew 收集器
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
它是 Serial 收集器的多线程版本
@ -290,7 +318,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 4. Serial Old 收集器
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
Serial 收集器的老年代版本也是给 Client 场景下的虚拟机使用如果用在 Server 场景下它有两大用途
@ -299,7 +327,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 5. Parallel Old 收集器
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
Parallel Scavenge 收集器的老年代版本
@ -307,7 +335,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
### 6. CMS 收集器
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
CMSConcurrent Mark SweepMark Sweep 指的是标记 - 清除算法
@ -332,17 +360,17 @@ G1Garbage-First它是一款面向服务端应用的垃圾收集器
堆被分为新生代和老年代其它收集器进行收集的范围都是整个新生代或者老年代 G1 可以直接对新生代和老年代一起回收
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
G1 把堆划分成多个大小相等的独立区域Region新生代和老年代不再物理隔离
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
通过引入 Region 的概念从而将原来的一整块内存空间划分成多个的小空间使得每个小空间可以单独进行垃圾回收这种划分方法带来了很大的灵活性使得可预测的停顿时间模型成为可能通过记录每个 Region 垃圾回收时间以及回收所获得的空间这两个值是通过过去回收的经验获得并维护一个优先列表每次根据允许的收集时间优先回收价值最大的 Region
每个 Region 都有一个 Remembered Set用来记录该 Region 对象的引用对象所在的 Region通过使用 Remembered Set在做可达性分析的时候就可以避免全堆扫描
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/>
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
如果不计算维护 Remembered Set 的操作G1 收集器的运作大致可划分为以下几个步骤
@ -430,15 +458,15 @@ G1 把堆划分成多个大小相等的独立区域Region新生代和
## 类的生命周期
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/335fe19c-4a76-45ab-9320-88c90d6a0d7e.png" width="600px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/335fe19c-4a76-45ab-9320-88c90d6a0d7e.png" width="600px"> </div><br>
包括以下 7 个阶段
- **加载Loading**
- **验证Verification**
- **准备Preparation**
- **解析Resolution**
- **初始化Initialization**
- **加载Loading**
- **验证Verification**
- **准备Preparation**
- **解析Resolution**
- **初始化Initialization**
- 使用Using
- 卸载Unloading
@ -600,7 +628,7 @@ System.out.println(ConstClass.HELLOWORLD);
下图展示了类加载器之间的层次关系称为双亲委派模型Parents Delegation Model该模型要求除了顶层的启动类加载器外其它的类加载器都要有自己的父类加载器这里的父子关系一般通过组合关系Composition来实现而不是继承关系Inheritance
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0dd2d40a-5b2b-4d45-b176-e75a4cd4bdbf.png" width="500px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0dd2d40a-5b2b-4d45-b176-e75a4cd4bdbf.png" width="500px"> </div><br>
### 1. 工作过程
@ -725,3 +753,10 @@ public class FileSystemClassLoader extends ClassLoader {
- [深入探讨 Java 类加载器](https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#code6)
- [Guide to WeakHashMap in Java](http://www.baeldung.com/java-weakhashmap)
- [Tomcat example source code file (ConcurrentCache.java)](https://alvinalexander.com/java/jwarehouse/apache-tomcat-6.0.16/java/org/apache/el/util/ConcurrentCache.java.shtml)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,12 @@
[TOC]
<!-- GFM-TOC -->
* [1. 求开方](#1-求开方)
* [2. 大于给定元素的最小元素](#2-大于给定元素的最小元素)
* [3. 有序数组的 Single Element](#3-有序数组的-single-element)
* [4. 第一个错误的版本](#4-第一个错误的版本)
* [5. 旋转数组的最小数字](#5-旋转数组的最小数字)
* [6. 查找区间](#6-查找区间)
<!-- GFM-TOC -->
正常实现**
@ -25,11 +33,11 @@ public int binarySearch(int[] nums, int key) {
}
```
**时间复杂度**
**时间复杂度**
二分查找也称为折半查找每次都能将查找区间减半这种折半特性的算法时间复杂度为 O(logN)
**m 计算**
**m 计算**
有两种计算中值 m 的方式
@ -38,14 +46,14 @@ public int binarySearch(int[] nums, int key) {
l + h 可能出现加法溢出也就是说加法的结果大于整型能够表示的范围但是 l h 都为正数因此 h - l 不会出现加法溢出问题所以最好使用第二种计算法方法
**未成功查找的返回值**
**未成功查找的返回值**
循环退出时如果仍然没有查找到 key那么表示查找失败可以有两种返回值
- -1以一个错误码表示没有查找到 key
- l key 插入到 nums 中的正确位置
**变种**
**变种**
二分查找可以有很多变种变种实现要注意边界值的判断例如在一个有重复元素的数组中查找 key 的最左位置的实现如下
@ -293,3 +301,10 @@ private int binarySearch(int[] nums, int target) {
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,6 +1,21 @@
[TOC]
<!-- GFM-TOC -->
* [1. 统计两个数的二进制表示有多少位不同](#1-统计两个数的二进制表示有多少位不同)
* [2. 数组中唯一一个不重复的元素](#2-数组中唯一一个不重复的元素)
* [3. 找出数组中缺失的那个数](#3-找出数组中缺失的那个数)
* [4. 数组中不重复的两个元素](#4-数组中不重复的两个元素)
* [5. 翻转一个数的比特位](#5-翻转一个数的比特位)
* [6. 不用额外变量交换两个整数](#6-不用额外变量交换两个整数)
* [7. 判断一个数是不是 2 n 次方](#7-判断一个数是不是-2--n-次方)
* [8. 判断一个数是不是 4 n 次方](#8--判断一个数是不是-4--n-次方)
* [9. 判断一个数的位级表示是否不会出现连续的 0 1](#9-判断一个数的位级表示是否不会出现连续的-0--1)
* [10. 求一个数的补码](#10-求一个数的补码)
* [11. 实现整数的加法](#11-实现整数的加法)
* [12. 字符串数组最大乘积](#12-字符串数组最大乘积)
* [13. 统计从 0 \~ n 每个数的二进制表示中 1 的个数](#13-统计从-0-\~-n-每个数的二进制表示中-1-的个数)
<!-- GFM-TOC -->
**基本原理**
**基本原理**
0s 表示一串 01s 表示一串 1
@ -26,7 +41,7 @@ x ^ x = 0 x & x = x x | x = x
- \>\>\> n 为无符号右移左边会补上 0
- &lt;&lt; n 为算术左移相当于乘以 2<sup>n</sup>
** mask 计算**
** mask 计算**
要获取 111111111 0 取反即可\~0
@ -36,7 +51,7 @@ x ^ x = 0 x & x = x x | x = x
要得到 1 i 位为 0 mask只需将 1 i 位为 1 mask 取反 \~((1&lt;&lt;i)-1)
**Java 中的位操作**
**Java 中的位操作**
```html
static int Integer.bitCount(); // 统计 1 的数量
@ -425,3 +440,10 @@ public int[] countBits(int num) {
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,8 @@
[TOC]
<!-- GFM-TOC -->
* [1. 给表达式加括号](#1-给表达式加括号)
* [2. 不同的二叉搜索树](#2-不同的二叉搜索树)
<!-- GFM-TOC -->
# 1. 给表达式加括号
@ -104,3 +108,10 @@ private List<TreeNode> generateSubtrees(int s, int e) {
return res;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,44 @@
[TOC]
<!-- GFM-TOC -->
* [斐波那契数列](#斐波那契数列)
* [1. 爬楼梯](#1-爬楼梯)
* [2. 强盗抢劫](#2-强盗抢劫)
* [3. 强盗在环形街区抢劫](#3-强盗在环形街区抢劫)
* [4. 信件错排](#4-信件错排)
* [5. 母牛生产](#5-母牛生产)
* [矩阵路径](#矩阵路径)
* [1. 矩阵的最小路径和](#1-矩阵的最小路径和)
* [2. 矩阵的总路径数](#2-矩阵的总路径数)
* [数组区间](#数组区间)
* [1. 数组区间和](#1-数组区间和)
* [2. 数组中等差递增子区间的个数](#2-数组中等差递增子区间的个数)
* [分割整数](#分割整数)
* [1. 分割整数的最大乘积](#1-分割整数的最大乘积)
* [2. 按平方数来分割整数](#2-按平方数来分割整数)
* [3. 分割整数构成字母字符串](#3-分割整数构成字母字符串)
* [最长递增子序列](#最长递增子序列)
* [1. 最长递增子序列](#1-最长递增子序列)
* [2. 一组整数对能够构成的最长链](#2-一组整数对能够构成的最长链)
* [3. 最长摆动子序列](#3-最长摆动子序列)
* [最长公共子序列](#最长公共子序列)
* [0-1 背包](#0-1-背包)
* [1. 划分数组为和相等的两部分](#1-划分数组为和相等的两部分)
* [2. 改变一组数的正负号使得它们的和为一给定数](#2-改变一组数的正负号使得它们的和为一给定数)
* [3. 01 字符构成最多的字符串](#3-01-字符构成最多的字符串)
* [4. 找零钱的最少硬币数](#4-找零钱的最少硬币数)
* [5. 找零钱的硬币数组合](#5-找零钱的硬币数组合)
* [6. 字符串按单词列表分割](#6-字符串按单词列表分割)
* [7. 组合总和](#7-组合总和)
* [股票交易](#股票交易)
* [1. 需要冷却期的股票交易](#1-需要冷却期的股票交易)
* [2. 需要交易费用的股票交易](#2-需要交易费用的股票交易)
* [3. 只能进行两次的股票交易](#3-只能进行两次的股票交易)
* [4. 只能进行 k 次的股票交易](#4-只能进行-k-次的股票交易)
* [字符串编辑](#字符串编辑)
* [1. 删除两个字符串的字符使它们相等](#1-删除两个字符串的字符使它们相等)
* [2. 编辑距离](#2-编辑距离)
* [3. 复制粘贴字符](#3-复制粘贴字符)
<!-- GFM-TOC -->
@ -20,7 +60,7 @@
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=dp[i-1]+dp[i-2]" class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/14fe1e71-8518-458f-a220-116003061a83.png" width="200px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/14fe1e71-8518-458f-a220-116003061a83.png" width="200px"> </div><br>
考虑到 dp[i] 只与 dp[i - 1] dp[i - 2] 有关因此可以只用两个变量来存储 dp[i - 1] dp[i - 2]使得原来的 O(N) 空间复杂度优化为 O(1) 复杂度
@ -53,7 +93,7 @@ public int climbStairs(int n) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=max(dp[i-2]+nums[i],dp[i-1])" class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2de794ca-aa7b-48f3-a556-a0e2708cb976.jpg" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2de794ca-aa7b-48f3-a556-a0e2708cb976.jpg" width="350px"> </div><br>
```java
public int rob(int[] nums) {
@ -109,7 +149,7 @@ private int rob(int[] nums, int first, int last) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=(i-1)*dp[i-2]+(i-1)*dp[i-1]" class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/da1f96b9-fd4d-44ca-8925-fb14c5733388.png" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/da1f96b9-fd4d-44ca-8925-fb14c5733388.png" width="350px"> </div><br>
## 5. 母牛生产
@ -121,7 +161,7 @@ private int rob(int[] nums, int first, int last) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i]=dp[i-1]+dp[i-3]" class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/879814ee-48b5-4bcb-86f5-dcc400cb81ad.png" width="250px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/879814ee-48b5-4bcb-86f5-dcc400cb81ad.png" width="250px"> </div><br>
# 矩阵路径
@ -171,7 +211,7 @@ public int minPathSum(int[][] grid) {
题目描述统计从矩阵左上角到右下角的路径总数每次只能向右或者向下移动
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dc82f0f3-c1d4-4ac8-90ac-d5b32a9bd75a.jpg" width="">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dc82f0f3-c1d4-4ac8-90ac-d5b32a9bd75a.jpg" width=""> </div><br>
```java
public int uniquePaths(int m, int n) {
@ -392,9 +432,9 @@ public int numDecodings(String s) {
# 最长递增子序列
已知一个序列 {S<sub>1</sub>, S<sub>2</sub>,...,S<sub>n</sub>}取出若干数组成新的序列 {S<sub>i1</sub>, S<sub>i2</sub>,..., S<sub>im</sub>}其中 i1i2 ... im 保持递增即新序列中各个数仍然保持原数列中的先后顺序称新序列为原序列的一个 **子序列**
已知一个序列 {S<sub>1</sub>, S<sub>2</sub>,...,S<sub>n</sub>}取出若干数组成新的序列 {S<sub>i1</sub>, S<sub>i2</sub>,..., S<sub>im</sub>}其中 i1i2 ... im 保持递增即新序列中各个数仍然保持原数列中的先后顺序称新序列为原序列的一个 **子序列**
如果在子序列中当下标 ix > iy S<sub>ix</sub> > S<sub>iy</sub>称子序列为原序列的一个 **递增子序列**
如果在子序列中当下标 ix > iy S<sub>ix</sub> > S<sub>iy</sub>称子序列为原序列的一个 **递增子序列**
定义一个数组 dp 存储最长递增子序列的长度dp[n] 表示以 S<sub>n</sub> 结尾的序列的最长递增子序列长度对于一个递增子序列 {S<sub>i1</sub>, S<sub>i2</sub>,...,S<sub>im</sub>}如果 im < n 并且 S<sub>im</sub> < S<sub>n</sub>此时 {S<sub>i1</sub>, S<sub>i2</sub>,..., S<sub>im</sub>, S<sub>n</sub>} 为一个递增子序列递增子序列的长度增加 1满足上述条件的递增子序列中长度最长的那个递增子序列就是要找的在长度最长的递增子序列上加上 S<sub>n</sub> 就构成了以 S<sub>n</sub> 为结尾的最长递增子序列因此 dp[n] = max{ dp[i]+1 | S<sub>i</sub> < S<sub>n</sub> && i < n}
@ -402,7 +442,7 @@ public int numDecodings(String s) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[n]=max\{1,dp[i]+1|S_i<S_n\&\&i<n\}" class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ee994da4-0fc7-443d-ac56-c08caf00a204.jpg" width="350px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ee994da4-0fc7-443d-ac56-c08caf00a204.jpg" width="350px"> </div><br>
对于一个长度为 N 的序列最长递增子序列并不一定会以 S<sub>N</sub> 为结尾因此 dp[N] 不是序列的最长递增子序列的长度需要遍历 dp 数组找出最大值才是所要的结果max{ dp[i] | 1 <= i <= N} 即为所求
@ -575,7 +615,7 @@ public int wiggleMaxLength(int[] nums) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i][j]=\left\{\begin{array}{rcl}dp[i-1][j-1]&&{S1_i==S2_j}\\max(dp[i-1][j],dp[i][j-1])&&{S1_i<>S2_j}\end{array}\right." class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ecd89a22-c075-4716-8423-e0ba89230e9a.jpg" width="450px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ecd89a22-c075-4716-8423-e0ba89230e9a.jpg" width="450px"> </div><br>
对于长度为 N 的序列 S<sub>1</sub> 和长度为 M 的序列 S<sub>2</sub>dp[N][M] 就是序列 S<sub>1</sub> 和序列 S<sub>2</sub> 的最长公共子序列长度
@ -615,7 +655,7 @@ public int lengthOfLCS(int[] nums1, int[] nums2) {
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[i][j]=max(dp[i-1][j],dp[i-1][j-w]+v)" class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8cb2be66-3d47-41ba-b55b-319fc68940d4.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8cb2be66-3d47-41ba-b55b-319fc68940d4.png" width="400px"> </div><br>
```java
// W 为背包总体积
@ -638,13 +678,13 @@ public int knapsack(int W, int N, int[] weights, int[] values) {
}
```
**空间优化**
**空间优化**
在程序实现时可以对 0-1 背包做优化观察状态转移方程可以知道 i 件物品的状态仅与前 i-1 件物品的状态有关因此可以将 dp 定义为一维数组其中 dp[j] 既可以表示 dp[i-1][j] 也可以表示 dp[i][j]此时
<!--<div align="center"><img src="https://latex.codecogs.com/gif.latex?dp[j]=max(dp[j],dp[j-w]+v)" class="mathjax-pic"/></div> <br>-->
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9ae89f16-7905-4a6f-88a2-874b4cac91f4.jpg" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9ae89f16-7905-4a6f-88a2-874b4cac91f4.jpg" width="300px"> </div><br>
因为 dp[j-w] 表示 dp[i-1][j-w]因此不能先求 dp[i][j-w]防止将 dp[i-1][j-w] 覆盖也就是说要先计算 dp[i][j] 再计算 dp[i][j-w]在程序实现时需要按倒序来循环求解
@ -663,7 +703,7 @@ public int knapsack(int W, int N, int[] weights, int[] values) {
}
```
**无法使用贪心算法的解释**
**无法使用贪心算法的解释**
0-1 背包问题无法使用贪心算法来求解也就是说不能按照先添加性价比最高的物品来达到最优这是因为这种方式可能造成背包空间的浪费从而无法达到最优考虑下面的物品和一个容量为 5 的背包如果先添加物品 0 再添加物品 1那么只能存放的价值为 16浪费了大小为 2 的空间最优的方式是存放物品 1 和物品 2价值为 22.
@ -673,7 +713,7 @@ public int knapsack(int W, int N, int[] weights, int[] values) {
| 1 | 2 | 10 | 5 |
| 2 | 3 | 12 | 4 |
**变种**
**变种**
- 完全背包物品数量为无限个
@ -1008,7 +1048,7 @@ public int combinationSum4(int[] nums, int target) {
题目描述交易之后需要有一天的冷却时间
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ffd96b99-8009-487c-8e98-11c9d44ef14f.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ffd96b99-8009-487c-8e98-11c9d44ef14f.png" width="300px"> </div><br>
```java
public int maxProfit(int[] prices) {
@ -1051,7 +1091,7 @@ The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
题目描述每交易一次都要支付一定的费用
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1e2c588c-72b7-445e-aacb-d55dc8a88c29.png" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1e2c588c-72b7-445e-aacb-d55dc8a88c29.png" width="300px"> </div><br>
```java
public int maxProfit(int[] prices, int fee) {
@ -1263,3 +1303,10 @@ public int minSteps(int n) {
return dp[n];
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,13 @@
[TOC]
<!-- GFM-TOC -->
* [1. 有序数组的 Two Sum](#1-有序数组的-two-sum)
* [2. 两数平方和](#2-两数平方和)
* [3. 反转字符串中的元音字符](#3-反转字符串中的元音字符)
* [4. 回文字符串](#4-回文字符串)
* [5. 归并两个有序数组](#5-归并两个有序数组)
* [6. 判断链表是否存在环](#6-判断链表是否存在环)
* [7. 最长子序列](#7-最长子序列)
<!-- GFM-TOC -->
双指针主要用于遍历数组两个指针指向不同的元素从而协同完成任务
@ -23,7 +32,7 @@ Output: index1=1, index2=2
数组中的元素最多遍历一次时间复杂度为 O(N)只使用了两个额外变量空间复杂度为 O(1)
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/437cb54c-5970-4ba9-b2ef-2541f7d6c81e.gif" width="200px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/437cb54c-5970-4ba9-b2ef-2541f7d6c81e.gif" width="200px"> </div><br>
```java
public int[] twoSum(int[] numbers, int target) {
@ -93,7 +102,7 @@ Explanation: 1 * 1 + 2 * 2 = 5
Given s = "leetcode", return "leotcede".
```
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a7cb8423-895d-4975-8ef8-662a0029c772.png" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a7cb8423-895d-4975-8ef8-662a0029c772.png" width="400px"> </div><br>
使用双指针一个指针从头向尾遍历一个指针从尾到头遍历当两个指针都遍历到元音字符时交换这两个元音字符
@ -102,7 +111,7 @@ Given s = "leetcode", return "leotcede".
- 时间复杂度为 O(N)只需要遍历所有元素一次
- 空间复杂度 O(1)只需要使用两个额外变量
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ef25ff7c-0f63-420d-8b30-eafbeea35d11.gif" width="400px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ef25ff7c-0f63-420d-8b30-eafbeea35d11.gif" width="400px"> </div><br>
```java
private final static HashSet<Character> vowels = new HashSet<>(
@ -146,7 +155,7 @@ Explanation: You could delete the character 'c'.
使用双指针可以很容易判断一个字符串是否是回文字符串令一个指针从左到右遍历一个指针从右到左遍历这两个指针同时移动一个位置每次都判断两个指针指向的字符是否相同如果都相同字符串才是具有左右对称性质的回文字符串
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/fcc941ec-134b-4dcd-bc86-1702fd305300.gif" width="250px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/fcc941ec-134b-4dcd-bc86-1702fd305300.gif" width="250px"> </div><br>
本题的关键是处理删除一个字符在使用双指针遍历字符串时如果出现两个指针指向的字符不相等的情况我们就试着删除一个字符再判断删除完之后的字符串是否是回文字符串
@ -154,7 +163,7 @@ Explanation: You could delete the character 'c'.
在试着删除字符时我们既可以删除左指针指向的字符也可以删除右指针指向的字符
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/db5f30a7-8bfa-4ecc-ab5d-747c77818964.gif" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/db5f30a7-8bfa-4ecc-ab5d-747c77818964.gif" width="300px"> </div><br>
```java
public boolean validPalindrome(String s) {
@ -281,3 +290,10 @@ private boolean isSubstr(String s, String target) {
return j == target.length();
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,10 +1,16 @@
[TOC]
<!-- GFM-TOC -->
* [1. 数组中两个数的和为给定值](#1-数组中两个数的和为给定值)
* [2. 判断数组是否含有重复元素](#2-判断数组是否含有重复元素)
* [3. 最长和谐序列](#3-最长和谐序列)
* [4. 最长连续序列](#4-最长连续序列)
<!-- GFM-TOC -->
哈希表使用 O(N) 空间复杂度存储数据并且以 O(1) 时间复杂度求解问题
- Java 中的 **HashSet** 用于存储一个集合可以查找元素是否在集合中如果元素有穷并且范围不大那么可以用一个布尔数组来存储一个元素是否存在例如对于只有小写字符的元素就可以用一个长度为 26 的布尔数组来存储一个字符集合使得空间复杂度降低为 O(1)
- Java 中的 **HashSet** 用于存储一个集合可以查找元素是否在集合中如果元素有穷并且范围不大那么可以用一个布尔数组来存储一个元素是否存在例如对于只有小写字符的元素就可以用一个长度为 26 的布尔数组来存储一个字符集合使得空间复杂度降低为 O(1)
Java 中的 **HashMap** 主要用于映射关系从而把两个元素联系起来HashMap 也可以用来对元素进行计数统计此时键为元素值为计数 HashSet 类似如果元素有穷并且范围不大可以用整型数组来进行统计在对一个内容进行压缩或者其它转换时利用 HashMap 可以把原始内容和转换后的内容联系起来例如在一个简化 url 的系统中 [Leetcdoe : 535. Encode and Decode TinyURL (Medium)
Java 中的 **HashMap** 主要用于映射关系从而把两个元素联系起来HashMap 也可以用来对元素进行计数统计此时键为元素值为计数 HashSet 类似如果元素有穷并且范围不大可以用整型数组来进行统计在对一个内容进行压缩或者其它转换时利用 HashMap 可以把原始内容和转换后的内容联系起来例如在一个简化 url 的系统中 [Leetcdoe : 535. Encode and Decode TinyURL (Medium)
[Leetcode](https://leetcode.com/problems/encode-and-decode-tinyurl/description/)利用 HashMap 就可以存储精简后的 url 到原始 url 的映射使得不仅可以显示简化的 url也可以根据简化的 url 得到原始 url 从而定位到正确的资源<EFBFBD>) / [力扣](https://leetcode-cn.com/problems/encode-and-decode-tinyurl/description/)利用 HashMap 就可以存储精简后的 url 到原始 url 的映射使得不仅可以显示简化的 url也可以根据简化的 url 得到原始 url 从而定位到正确的资源<EFBFBD>)
@ -125,3 +131,10 @@ private int maxCount(Map<Integer, Integer> countForNum) {
return max;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,13 @@
[TOC]
<!-- GFM-TOC -->
* [二分图](#二分图)
* [1. 判断是否为二分图](#1-判断是否为二分图)
* [拓扑排序](#拓扑排序)
* [1. 课程安排的合法性](#1-课程安排的合法性)
* [2. 课程安排的顺序](#2-课程安排的顺序)
* [并查集](#并查集)
* [1. 冗余连接](#1-冗余连接)
<!-- GFM-TOC -->
# 二分图
@ -254,3 +263,10 @@ private class UF {
}
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,15 @@
[TOC]
<!-- GFM-TOC -->
* [1. 字符串循环移位包含](#1-字符串循环移位包含)
* [2. 字符串循环移位](#2-字符串循环移位)
* [3. 字符串中单词的翻转](#3-字符串中单词的翻转)
* [4. 两个字符串包含的字符是否完全相同](#4-两个字符串包含的字符是否完全相同)
* [5. 计算一组字符集合可以组成的回文字符串的最大长度](#5-计算一组字符集合可以组成的回文字符串的最大长度)
* [6. 字符串同构](#6-字符串同构)
* [7. 回文子字符串个数](#7-回文子字符串个数)
* [8. 判断一个整数是否是回文数](#8-判断一个整数是否是回文数)
* [9. 统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数](#9-统计二进制字符串中连续-1-和连续-0-数量相同的子字符串个数)
<!-- GFM-TOC -->
# 1. 字符串循环移位包含
@ -224,3 +235,10 @@ public int countBinarySubstrings(String s) {
return count;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,14 +1,24 @@
[TOC]
<!-- GFM-TOC -->
* [快速选择](#快速选择)
* [](#)
* [1. Kth Element](#1-kth-element)
* [桶排序](#桶排序)
* [1. 出现频率最多的 k 个元素](#1-出现频率最多的-k-个元素)
* [2. 按照字符出现次数对字符串排序](#2-按照字符出现次数对字符串排序)
* [荷兰国旗问题](#荷兰国旗问题)
* [1. 按颜色进行排序](#1-按颜色进行排序)
<!-- GFM-TOC -->
# 快速选择
用于求解 **Kth Element** 问题也就是第 K 个元素的问题
用于求解 **Kth Element** 问题也就是第 K 个元素的问题
可以使用快速排序的 partition() 进行实现需要先打乱数组否则最坏情况下时间复杂度为 O(N<sup>2</sup>)
#
用于求解 **TopK Elements** 问题也就是 K 个最小元素的问题可以维护一个大小为 K 的最小堆最小堆中的元素就是最小元素最小堆需要使用大顶堆来实现大顶堆表示堆顶元素是堆中最大元素这是因为我们要得到 k 个最小的元素因此当遍历到一个新的元素时需要知道这个新元素是否比堆中最大的元素更小更小的话就把堆中最大元素去除并将新元素添加到堆中所以我们需要很容易得到最大元素并移除最大元素大顶堆就能很好满足这个要求
用于求解 **TopK Elements** 问题也就是 K 个最小元素的问题可以维护一个大小为 K 的最小堆最小堆中的元素就是最小元素最小堆需要使用大顶堆来实现大顶堆表示堆顶元素是堆中最大元素这是因为我们要得到 k 个最小的元素因此当遍历到一个新的元素时需要知道这个新元素是否比堆中最大的元素更小更小的话就把堆中最大元素去除并将新元素添加到堆中所以我们需要很容易得到最大元素并移除最大元素大顶堆就能很好满足这个要求
堆也可以用于求解 Kth Element 问题得到了大小为 k 的最小堆之后因为使用了大顶堆来实现因此堆顶元素就是第 k 大的元素
@ -29,7 +39,7 @@ Output: 5
题目描述找到倒数第 k 个的元素
**排序** 时间复杂度 O(NlogN)空间复杂度 O(1)
**排序** 时间复杂度 O(NlogN)空间复杂度 O(1)
```java
public int findKthLargest(int[] nums, int k) {
@ -38,7 +48,7 @@ public int findKthLargest(int[] nums, int k) {
}
```
**** 时间复杂度 O(NlogK)空间复杂度 O(K)
**** 时间复杂度 O(NlogK)空间复杂度 O(K)
```java
public int findKthLargest(int[] nums, int k) {
@ -52,7 +62,7 @@ public int findKthLargest(int[] nums, int k) {
}
```
**快速选择** 时间复杂度 O(N)空间复杂度 O(1)
**快速选择** 时间复杂度 O(N)空间复杂度 O(1)
```java
public int findKthLargest(int[] nums, int k) {
@ -190,7 +200,7 @@ public String frequencySort(String s) {
有三种颜色的球算法的目标是将这三种球按颜色顺序正确地排列它其实是三向切分快速排序的一种变种在三向切分快速排序中每次切分都将数组分成三个区间小于切分元素等于切分元素大于切分元素而该算法是将数组分成三个区间等于红色等于白色等于蓝色
![](pics/7a3215ec-6fb7-4935-8b0d-cb408208f7cb.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7a3215ec-6fb7-4935-8b0d-cb408208f7cb.png"/> </div><br>
## 1. 按颜色进行排序
@ -226,3 +236,10 @@ private void swap(int[] nums, int i, int j) {
nums[j] = t;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,10 +1,38 @@
[TOC]
<!-- GFM-TOC -->
* [BFS](#bfs)
* [1. 计算在网格中从原点到特定点的最短路径长度](#1-计算在网格中从原点到特定点的最短路径长度)
* [2. 组成整数的最小平方数数量](#2-组成整数的最小平方数数量)
* [3. 最短单词路径](#3-最短单词路径)
* [DFS](#dfs)
* [1. 查找最大的连通面积](#1-查找最大的连通面积)
* [2. 矩阵中的连通分量数目](#2-矩阵中的连通分量数目)
* [3. 好友关系的连通分量数目](#3-好友关系的连通分量数目)
* [4. 填充封闭区域](#4-填充封闭区域)
* [5. 能到达的太平洋和大西洋的区域](#5-能到达的太平洋和大西洋的区域)
* [Backtracking](#backtracking)
* [1. 数字键盘组合](#1-数字键盘组合)
* [2. IP 地址划分](#2-ip-地址划分)
* [3. 在矩阵中寻找字符串](#3-在矩阵中寻找字符串)
* [4. 输出二叉树中所有从根到叶子的路径](#4-输出二叉树中所有从根到叶子的路径)
* [5. 排列](#5-排列)
* [6. 含有相同元素求排列](#6-含有相同元素求排列)
* [7. 组合](#7-组合)
* [8. 组合求和](#8-组合求和)
* [9. 含有相同元素的组合求和](#9-含有相同元素的组合求和)
* [10. 1-9 数字的组合求和](#10-1-9-数字的组合求和)
* [11. 子集](#11-子集)
* [12. 含有相同元素求子集](#12-含有相同元素求子集)
* [13. 分割字符串使得每个部分都是回文数](#13-分割字符串使得每个部分都是回文数)
* [14. 数独](#14-数独)
* [15. N 皇后](#15-n-皇后)
<!-- GFM-TOC -->
深度优先搜索和广度优先搜索广泛运用于树和图中但是它们的应用远远不止如此
# BFS
![](pics/95903878-725b-4ed9-bded-bc4aae0792a9.jpg)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/95903878-725b-4ed9-bded-bc4aae0792a9.jpg"/> </div><br>
广度优先搜索一层一层地进行遍历每层遍历都以上一层遍历的结果作为起点遍历一个距离能访问到的所有节点需要注意的是遍历过的节点不能再次被遍历
@ -24,7 +52,7 @@
- 4 -> {}
- 3 -> {}
每一层遍历的节点都与根节点距离相同 d<sub>i</sub> 表示第 i 个节点与根节点的距离推导出一个结论对于先遍历的节点 i 与后遍历的节点 j d<sub>i</sub> <= d<sub>j</sub>利用这个结论可以求解最短路径等 **最优解** 问题第一次遍历到目的节点其所经过的路径为最短路径应该注意的是使用 BFS 只能求解无权图的最短路径无权图是指从一个节点到另一个节点的代价都记为 1
每一层遍历的节点都与根节点距离相同 d<sub>i</sub> 表示第 i 个节点与根节点的距离推导出一个结论对于先遍历的节点 i 与后遍历的节点 j d<sub>i</sub> <= d<sub>j</sub>利用这个结论可以求解最短路径等 **最优解** 问题第一次遍历到目的节点其所经过的路径为最短路径应该注意的是使用 BFS 只能求解无权图的最短路径无权图是指从一个节点到另一个节点的代价都记为 1
在程序实现 BFS 时需要考虑以下问题
@ -241,13 +269,13 @@ private int getShortestPath(List<Integer>[] graphic, int start, int end) {
# DFS
![](pics/74dc31eb-6baa-47ea-ab1c-d27a0ca35093.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/74dc31eb-6baa-47ea-ab1c-d27a0ca35093.png"/> </div><br>
广度优先搜索一层一层遍历每一层得到的所有新节点要用队列存储起来以备下一层遍历的时候再遍历
而深度优先搜索在得到一个新节点时立即对新节点进行遍历从节点 0 出发开始遍历得到到新节点 6 立马对新节点 6 进行遍历得到新节点 4如此反复以这种方式遍历新节点直到没有新节点了此时返回返回到根节点 0 的情况是继续对根节点 0 进行遍历得到新节点 2然后继续以上步骤
从一个节点出发使用 DFS 对一个图进行遍历时能够遍历到的节点都是从初始节点可达的DFS 常用来求解这种 **可达性** 问题
从一个节点出发使用 DFS 对一个图进行遍历时能够遍历到的节点都是从初始节点可达的DFS 常用来求解这种 **可达性** 问题
在程序实现 DFS 时需要考虑以下问题
@ -549,8 +577,8 @@ private void dfs(int r, int c, boolean[][] canReach) {
Backtracking回溯属于 DFS
- 普通 DFS 主要用在 **可达性问题** 这种问题只需要执行到特点的位置然后返回即可
- Backtracking 主要用于求解 **排列组合** 问题例如有 { 'a','b','c' } 三个字符求解所有由这三个字符排列得到的字符串这种问题在执行到特定的位置返回之后还会继续执行求解过程
- 普通 DFS 主要用在 **可达性问题** 这种问题只需要执行到特点的位置然后返回即可
- Backtracking 主要用于求解 **排列组合** 问题例如有 { 'a','b','c' } 三个字符求解所有由这三个字符排列得到的字符串这种问题在执行到特定的位置返回之后还会继续执行求解过程
因为 Backtracking 不是立即返回而要继续求解因此在程序实现时需要注意对元素的标记问题
@ -563,7 +591,7 @@ Backtracking回溯属于 DFS。
[Leetcode](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/) / [力扣](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/description/)
![](pics/9823768c-212b-4b1a-b69a-b3f59e07b977.jpg)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9823768c-212b-4b1a-b69a-b3f59e07b977.jpg"/> </div><br>
```html
Input:Digit string "23"
@ -1166,7 +1194,7 @@ private boolean isPalindrome(String s, int begin, int end) {
[Leetcode](https://leetcode.com/problems/sudoku-solver/description/) / [力扣](https://leetcode-cn.com/problems/sudoku-solver/description/)
![](pics/0e8fdc96-83c1-4798-9abe-45fc91d70b9d.png)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/0e8fdc96-83c1-4798-9abe-45fc91d70b9d.png"/> </div><br>
```java
private boolean[][] rowsUsed = new boolean[9][10];
@ -1225,7 +1253,7 @@ private int cubeNum(int i, int j) {
[Leetcode](https://leetcode.com/problems/n-queens/description/) / [力扣](https://leetcode-cn.com/problems/n-queens/description/)
![](pics/067b310c-6877-40fe-9dcf-10654e737485.jpg)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/067b310c-6877-40fe-9dcf-10654e737485.jpg"/> </div><br>
n\*n 的矩阵中摆放 n 个皇后并且每个皇后不能在同一行同一列同一对角线上求所有的 n 皇后的解
@ -1233,12 +1261,12 @@ private int cubeNum(int i, int j) {
45 度对角线标记数组的长度为 2 \* n - 1通过下图可以明确 (r, c) 的位置所在的数组下标为 r + c
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9c422923-1447-4a3b-a4e1-97e663738187.jpg" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/9c422923-1447-4a3b-a4e1-97e663738187.jpg" width="300px"> </div><br>
135 度对角线标记数组的长度也是 2 \* n - 1(r, c) 的位置所在的数组下标为 n - 1 - (r - c)
<img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7a85e285-e152-4116-b6dc-3fab27ba9437.jpg" width="300px">
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7a85e285-e152-4116-b6dc-3fab27ba9437.jpg" width="300px"> </div><br>
```java
private List<List<String>> solutions;
@ -1286,3 +1314,10 @@ private void backtracking(int row) {
}
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,30 @@
[TOC]
<!-- GFM-TOC -->
* [素数分解](#素数分解)
* [整除](#整除)
* [最大公约数最小公倍数](#最大公约数最小公倍数)
* [1. 生成素数序列](#1-生成素数序列)
* [2. 最大公约数](#2-最大公约数)
* [3. 使用位操作和减法求解最大公约数](#3-使用位操作和减法求解最大公约数)
* [进制转换](#进制转换)
* [1. 7 进制](#1-7-进制)
* [2. 16 进制](#2-16-进制)
* [3. 26 进制](#3-26-进制)
* [阶乘](#阶乘)
* [1. 统计阶乘尾部有多少个 0](#1-统计阶乘尾部有多少个-0)
* [字符串加法减法](#字符串加法减法)
* [1. 二进制加法](#1-二进制加法)
* [2. 字符串加法](#2-字符串加法)
* [相遇问题](#相遇问题)
* [1. 改变数组元素使所有的数组元素都相等](#1-改变数组元素使所有的数组元素都相等)
* [多数投票问题](#多数投票问题)
* [1. 数组中出现次数多于 n / 2 的元素](#1-数组中出现次数多于-n--2-的元素)
* [其它](#其它)
* [1. 平方数](#1-平方数)
* [2. 3 n 次方](#2-3--n-次方)
* [3. 乘积数组](#3-乘积数组)
* [4. 找出数组中的乘积最大的三个数](#4-找出数组中的乘积最大的三个数)
<!-- GFM-TOC -->
# 素数分解
@ -295,7 +321,7 @@ Only two moves are needed (remember each move increments or decrements one eleme
设数组长度为 N则可以找到 N/2 a b 的组合使它们都移动到 m 的位置
**解法 1**
**解法 1**
先排序时间复杂度O(NlogN)
@ -313,7 +339,7 @@ public int minMoves2(int[] nums) {
}
```
**解法 2**
**解法 2**
使用快速选择找到中位数时间复杂度 O(N)
@ -505,3 +531,10 @@ public int maximumProduct(int[] nums) {
return Math.max(max1*max2*max3, max1*min1*min2);
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,18 @@
[TOC]
<!-- GFM-TOC -->
* [1. 把数组中的 0 移到末尾](#1-把数组中的-0-移到末尾)
* [2. 改变矩阵维度](#2-改变矩阵维度)
* [3. 找出数组中最长的连续 1](#3-找出数组中最长的连续-1)
* [4. 有序矩阵查找](#4-有序矩阵查找)
* [5. 有序矩阵的 Kth Element](#5-有序矩阵的-kth-element)
* [6. 一个数组元素在 [1, n] 之间其中一个数被替换为另一个数找出重复的数和丢失的数](#6-一个数组元素在-[1,-n]-之间其中一个数被替换为另一个数找出重复的数和丢失的数)
* [7. 找出数组中重复的数数组值在 [1, n] 之间](#7-找出数组中重复的数数组值在-[1,-n]-之间)
* [8. 数组相邻差值的个数](#8-数组相邻差值的个数)
* [9. 数组的度](#9-数组的度)
* [10. 对角元素相等的矩阵](#10-对角元素相等的矩阵)
* [11. 嵌套数组](#11-嵌套数组)
* [12. 分隔数组](#12-分隔数组)
<!-- GFM-TOC -->
# 1. 把数组中的 0 移到末尾
@ -447,3 +461,10 @@ public int maxChunksToSorted(int[] arr) {
return ret;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,12 @@
[TOC]
<!-- GFM-TOC -->
* [1. 用栈实现队列](#1-用栈实现队列)
* [2. 用队列实现栈](#2-用队列实现栈)
* [3. 最小值栈](#3-最小值栈)
* [4. 用栈实现括号匹配](#4-用栈实现括号匹配)
* [5. 数组中元素与下一个比它大的元素之间的距离](#5-数组中元素与下一个比它大的元素之间的距离)
* [6. 循环数组中比当前元素大的下一个元素](#6-循环数组中比当前元素大的下一个元素)
<!-- GFM-TOC -->
# 1. 用栈实现队列
@ -222,3 +230,10 @@ public int[] nextGreaterElements(int[] nums) {
return next;
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -1,4 +1,42 @@
[TOC]
<!-- GFM-TOC -->
* [递归](#递归)
* [1. 树的高度](#1-树的高度)
* [2. 平衡树](#2-平衡树)
* [3. 两节点的最长路径](#3-两节点的最长路径)
* [4. 翻转树](#4-翻转树)
* [5. 归并两棵树](#5-归并两棵树)
* [6. 判断路径和是否等于一个数](#6-判断路径和是否等于一个数)
* [7. 统计路径和等于一个数的路径数量](#7-统计路径和等于一个数的路径数量)
* [8. 子树](#8-子树)
* [9. 树的对称](#9-树的对称)
* [10. 最小路径](#10-最小路径)
* [11. 统计左叶子节点的和](#11-统计左叶子节点的和)
* [12. 相同节点值的最大路径长度](#12-相同节点值的最大路径长度)
* [13. 间隔遍历](#13-间隔遍历)
* [14. 找出二叉树中第二小的节点](#14-找出二叉树中第二小的节点)
* [层次遍历](#层次遍历)
* [1. 一棵树每层节点的平均数](#1-一棵树每层节点的平均数)
* [2. 得到左下角的节点](#2-得到左下角的节点)
* [前中后序遍历](#前中后序遍历)
* [1. 非递归实现二叉树的前序遍历](#1-非递归实现二叉树的前序遍历)
* [2. 非递归实现二叉树的后序遍历](#2-非递归实现二叉树的后序遍历)
* [3. 非递归实现二叉树的中序遍历](#3-非递归实现二叉树的中序遍历)
* [BST](#bst)
* [1. 修剪二叉查找树](#1-修剪二叉查找树)
* [2. 寻找二叉查找树的第 k 个元素](#2-寻找二叉查找树的第-k-个元素)
* [3. 把二叉查找树每个节点的值都加上比它大的节点的值](#3-把二叉查找树每个节点的值都加上比它大的节点的值)
* [4. 二叉查找树的最近公共祖先](#4-二叉查找树的最近公共祖先)
* [5. 二叉树的最近公共祖先](#5-二叉树的最近公共祖先)
* [6. 从有序数组中构造二叉查找树](#6-从有序数组中构造二叉查找树)
* [7. 根据有序链表构造平衡的二叉查找树](#7-根据有序链表构造平衡的二叉查找树)
* [8. 在二叉查找树中寻找两个节点使它们的和为一个给定值](#8-在二叉查找树中寻找两个节点使它们的和为一个给定值)
* [9. 在二叉查找树中查找两个节点之差的最小绝对值](#9-在二叉查找树中查找两个节点之差的最小绝对值)
* [10. 寻找二叉查找树中出现次数最多的值](#10-寻找二叉查找树中出现次数最多的值)
* [Trie](#trie)
* [1. 实现一个 Trie](#1-实现一个-trie)
* [2. 实现一个 Trie用来求前缀和](#2-实现一个-trie用来求前缀和)
<!-- GFM-TOC -->
# 递归
@ -1007,7 +1045,7 @@ private void inOrder(TreeNode node, List<Integer> nums) {
# Trie
![](pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg)
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
Trie又称前缀树或字典树用于判断字符串是否存在或者是否具有某种字符串前缀
@ -1142,3 +1180,10 @@ class MapSum {
}
```
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -31,3 +31,10 @@
- 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014.
- 编程之美小组. 编程之美[M]. 电子工业出版社, 2008.
- 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015.
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

View File

@ -31,3 +31,10 @@
- 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014.
- 编程之美小组. 编程之美[M]. 电子工业出版社, 2008.
- 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015.
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-1.png"></img></div>

Some files were not shown because too many files have changed in this diff Show More