From fbc0a1e837d519b7a66b4efa2375496973b7a6a1 Mon Sep 17 00:00:00 2001 From: Keqi Huang Date: Wed, 8 Aug 2018 11:59:34 +0800 Subject: [PATCH 01/53] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E6=95=B0=E6=8D=AE=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=96=B9=E9=9D=A2=E7=9A=84=E4=BC=98=E5=8C=96=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notes/MySQL.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/notes/MySQL.md b/notes/MySQL.md index 690425db..f2949801 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -304,6 +304,60 @@ Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explai 最有效的方式是使用索引来覆盖查询。 +### 3. 不要在列上使用函数和进行运算 + +在列上使用函数和计算将导致索引失效而进行全表扫描。 + +### 4. 尽量避免使用 != 或 not in 或 <> 等否定操作符 + +尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描。 + +### 5. 尽量避免使用 or 来连接条件 + +尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描。 + +### 6. 多个单列限制应该改成一个多列索引(复合索引)查询 + +因为 MySQL 只能使用一个单列索引,所以为多个列创建单列索引并不能提高 MySQL 的查询性能。正确的做法是将这多个要限定条件的列单独做成一个多列索引(复合索引)。 + +### 7. 查询时要按照复合索引的最左列开始查找 + +查询条件中没有使用复合索引的第一个字段,索引是不会被使用的。复合索引遵守“最左前缀”原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用。 + +假如我们只有一个复合索引 ```age_height_idx(age, height)``` + +如果我们使用 +```mysql +select * from user where height = 170; +``` +那么复合索引 ```age_height_idx(age, height)```将不会被使用。 + +### 8. 尽量不用范围查询 + +如果查询中的某个列有范围查询,则其右边所有列都无法使用索引优化查找。 + +比如说我们使用 +```mysql +select * from users where age > 16 and age < 30 and height = 180 +``` +则索引中 age 右边所有列都无法使用索引优化查找。换句话说,```age_height_idx(age, height)``` 索引等价于 ```age_height_idx(age)```。 + +### 9. 索引不要包含有NULL值的列 + +只要列中包含有 NULL 值,它就不会被包含在索引中,复合索引中只要有一列含有 NULL 值,那么这一列对于此复合索引就是无效的。 + +因此,在数据库设计时,除非有一个很特别的原因使用 NULL 值,不然尽量不要让字段的默认值为 NULL。 + +### 10. 隐式转换可能带来不好的影响 + +当 where 查询条件左右两侧类型不匹配的时候会发生隐式转换,隐式转换可能带来的不好影响就是导致索引失效而进行全表扫描。 + +下面的案例中,brith_date 是字符串,然而匹配的是整数类型,从而发生隐式转换。 + +```mysql +select from users where brith_date = 19950610; +``` + ## 重构查询方式 ### 1. 切分大查询 From 30d980c04fb91efc5a348aef1faa92e313d16233 Mon Sep 17 00:00:00 2001 From: Keqi Huang Date: Wed, 8 Aug 2018 12:04:42 +0800 Subject: [PATCH 02/53] Update MySQL.md --- notes/MySQL.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/notes/MySQL.md b/notes/MySQL.md index f2949801..e49087bf 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -358,6 +358,10 @@ select * from users where age > 16 and age < 30 and height = 180 select from users where brith_date = 19950610; ``` +### 11. like 语句的索引失效问题 + +当我们使用 like “value%” 的方式时是会使用索引的,但是对于 like “%value%” 这样的方式,必定会执行全表查询,这在数据量小的表,不存在性能问题,但是对于海量数据,全表扫描是非常可怕的事情。所以,根据业务需求,考虑使用 ElasticSearch 或 Solr 是个不错的方案。 + ## 重构查询方式 ### 1. 切分大查询 From 93a9fe11cb2b2c626206e5276132b1bc1961814a Mon Sep 17 00:00:00 2001 From: Keqi Huang Date: Wed, 8 Aug 2018 12:51:18 +0800 Subject: [PATCH 03/53] Update MySQL.md --- notes/MySQL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notes/MySQL.md b/notes/MySQL.md index e49087bf..02dbe638 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -483,3 +483,5 @@ MySQL 读写分离能提高性能的原因在于: - [How to create unique row ID in sharded databases?](https://stackoverflow.com/questions/788829/how-to-create-unique-row-id-in-sharded-databases) - [SQL Azure Federation – Introduction](http://geekswithblogs.net/shaunxu/archive/2012/01/07/sql-azure-federation-ndash-introduction.aspx "Title of this entry.") - [MySQL 索引背后的数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html) +- [服务端指南 数据存储篇 | MySQL(04) 索引使用的注意事项](http://blog.720ui.com/2017/mysql_core_04_index_item/) +- [mysql 聚簇索引 和聚簇索引 (二级索引)的 那些事](https://blog.csdn.net/bigtree_3721/article/details/51335479) From 4b0db3f578c0414fe29847a7e70d56f557789745 Mon Sep 17 00:00:00 2001 From: Keqi Huang Date: Wed, 8 Aug 2018 14:10:19 +0800 Subject: [PATCH 04/53] =?UTF-8?q?Update=20=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=8E=9F=E7=90=86.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notes/数据库系统原理.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index 151ffc0f..6b8fcd86 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -389,11 +389,11 @@ MVCC 不能解决幻读的问题,Next-Key Locks 就是为了解决这个问题 ## Gap Locks -锁定一个范围内的索引,例如当一个事务执行以下语句,其它事务就不能在 t.c 中插入 15。 +间隙锁锁住的是多行,是一个数据范围。间隙锁主要是为了防止出现幻读,但是它会把锁定范围扩大,有时候也会给我们带来麻烦。在数据库参数中,控制间隙锁的参数是 ```innodb_locks_unsafe_for_binlog```, 这个参数默认值是 OFF,也就是启用间隙锁,它是一个bool值,当值为 true 时表示 disable 间隙锁。那为了防止间隙锁是不是直接将 ```innodb_locaks_unsafe_for_binlog``` 设置为 ```true``` 就可以了呢?不一定!而且这个参数会影响到主从复制及灾难恢复,这个方法还尚待商量。 -```sql -SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE; -``` +间隙锁的出现主要集中在同一个事务中先 delete 后 insert 的情况下,当我们通过一个参数去删除一条记录的时候,如果参数在数据库中存在,那么这个时候产生的是普通行锁,锁住这个记录,然后删除,最后释放锁。如果这条记录不存在,问题就来了,数据库会扫描索引,发现这个记录不存在,这个时候的 delete 语句获取到的就是一个间隙锁,然后数据库会向左扫描扫到第一个比给定参数小的值,向右扫描扫描到第一个比给定参数大的值,然后以此为上下界限构建一个区间,进而锁住整个区间内的数据,一个特别容易出现死锁的间隙锁诞生了。 + +通过修改 ```innodb_locaks_unsafe_for_binlog``` 参数来取消间隙锁从而达到避免这种情况的死锁的方式尚待商量,那就只有修改代码逻辑,存在才删除,尽量避免去删除不存在的记录。 ## Next-Key Locks From 9a1a7ef04780063398576266ee677f1ab86d0068 Mon Sep 17 00:00:00 2001 From: luocaodan Date: Wed, 8 Aug 2018 22:56:45 +0800 Subject: [PATCH 05/53] =?UTF-8?q?Update=20=E5=89=91=E6=8C=87=20offer=20?= =?UTF-8?q?=E9=A2=98=E8=A7=A3.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notes/剑指 offer 题解.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/notes/剑指 offer 题解.md b/notes/剑指 offer 题解.md index 47d5d94e..5d9adbea 100644 --- a/notes/剑指 offer 题解.md +++ b/notes/剑指 offer 题解.md @@ -1298,6 +1298,7 @@ private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) ## 解题思路 +### 递归 ```java public void Mirror(TreeNode root) { @@ -1316,6 +1317,28 @@ private void swap(TreeNode root) } ``` +### 迭代 +```java +public void Mirror(TreeNode root) { + if (root == null) + return; + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + TreeNode p = stack.pop(); + if (p.left == null && p.right == null) + continue; + TreeNode left = p.left; + p.left = p.right; + p.right = left; + if (p.left != null) + stack.push(p.left); + if (p.right != null) + stack.push(p.right); + } +} +``` + # 28 对称的二叉树 [NowCder](https://www.nowcoder.com/practice/ff05d44dfdb04e1d83bdbdab320efbcb?tpId=13&tqId=11211&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) From c693786f509053f4d13fff4cf27082420a2de912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= Date: Thu, 9 Aug 2018 22:57:33 +0800 Subject: [PATCH 06/53] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b4e688d..8dbf0507 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ From e7d09f99768866dcf830a5f2ddb27804f0f59521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= Date: Thu, 9 Aug 2018 23:05:05 +0800 Subject: [PATCH 07/53] Update Group.md --- other/Group.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/Group.md b/other/Group.md index fee7b8bf..60ff3946 100644 --- a/other/Group.md +++ b/other/Group.md @@ -12,4 +12,4 @@ 交流群不讨论政治,不讨论有争议性的话题,不发表仇视言论,不传播谣言,不发布广告(招聘信息之类的可以)。 -

+

From 0d7909db6d01bdfa0a0fd9abaee469b9ddd2e3a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= Date: Thu, 9 Aug 2018 23:05:46 +0800 Subject: [PATCH 08/53] Add files via upload --- other/group.png | Bin 0 -> 152701 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 other/group.png diff --git a/other/group.png b/other/group.png new file mode 100644 index 0000000000000000000000000000000000000000..d0951ccefd39b8da763f574de0c45459a2b2b186 GIT binary patch literal 152701 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 PxQ>9pXJUB@s(=}-wB^t&TZyop0q3PwcUB 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%0DU^37k3vq#aYt%CQZ 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 IqSNvJ2CJEF2LJ#7 literal 0 HcmV?d00001 From dc6973b8e182a61fd17cb9fc23e66a75aa57d89b Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Thu, 9 Aug 2018 23:09:29 +0800 Subject: [PATCH 09/53] auto commit --- notes/HTTP.md | 33 +- notes/Leetcode 题解.md | 1971 +++++++++++++++++++------------------- notes/Linux.md | 9 +- notes/MySQL.md | 2 +- notes/剑指 offer 题解.md | 281 +++--- notes/消息队列.md | 6 +- notes/算法.md | 30 +- notes/缓存.md | 13 +- notes/设计模式.md | 31 +- 9 files changed, 1166 insertions(+), 1210 deletions(-) diff --git a/notes/HTTP.md b/notes/HTTP.md index 243dc283..537b24fe 100644 --- a/notes/HTTP.md +++ b/notes/HTTP.md @@ -45,7 +45,7 @@ * [二进制分帧层](#二进制分帧层) * [服务端推送](#服务端推送) * [首部压缩](#首部压缩) -* [八、GET 和 POST 的区别](#八get-和-post-的区别) +* [八、GET 和 POST 比较](#八get-和-post-比较) * [作用](#作用) * [参数](#参数) * [安全](#安全) @@ -61,13 +61,13 @@ ## URL -- URI(Uniform Resource Identifier,统一资源标识符) -- URL(Uniform Resource Locator,统一资源定位符) -- URN(Uniform Resource Name,统一资源名称),例如 urn:isbn:0-486-27557-4。 - URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基本都是 URL。 -


+- URI(Uniform Resource Identifier,统一资源标识符) +- URL(Uniform Resource Locator,统一资源定位符) +- URN(Uniform Resource Name,统一资源名称) + +

## 请求和响应报文 @@ -197,7 +197,7 @@ CONNECT www.example.com:443 HTTP/1.1 - **204 No Content** :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。 -- **206 Partial Content** :表示客户端进行了范围请求。响应报文包含由 Content-Range 指定范围的实体内容。 +- **206 Partial Content** :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。 ## 3XX 重定向 @@ -219,7 +219,7 @@ CONNECT www.example.com:443 HTTP/1.1 - **401 Unauthorized** :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。 -- **403 Forbidden** :请求被拒绝,服务器端没有必要给出拒绝的详细理由。 +- **403 Forbidden** :请求被拒绝。 - **404 Not Found** @@ -331,7 +331,7 @@ Set-Cookie: tasty_cookie=strawberry [page content] ``` -客户端之后对同一个服务器发送请求时,会从浏览器中读出 Cookie 信息通过 Cookie 请求首部字段发送给服务器。 +客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。 ```html GET /sample_page.html HTTP/1.1 @@ -382,9 +382,9 @@ Path 标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径 除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。 -Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在内存型数据库中,比如 Redis,效率会更高。 +Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。 -使用 Session 维护用户登录的过程如下: +使用 Session 维护用户登录状态的过程如下: - 用户进行登录时,用户提交包含用户名和密码的表单,放入 HTTP 请求报文中; - 服务器验证该用户名和密码; @@ -499,7 +499,7 @@ If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT ### 1. 短连接与长连接 -当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要断开一次 TCP 连接,连接建立和断开的开销会很大。 +当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。 长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。 @@ -688,7 +688,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer) ### 3. HTTPs 采用的加密方式 -HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证安全性,之后使用对称密钥加密进行通信来保证效率。(下图中的 Session Key 就是对称密钥) +HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)

@@ -717,7 +717,7 @@ HTTPs 的报文摘要功能之所以安全,是因为它结合了加密和认 ## HTTPs 的缺点 - 因为需要进行加密解密等过程,因此速度会更慢; -- 需要支付证书授权的高费用。 +- 需要支付证书授权的高额费用。 ## 配置 HTTPs @@ -727,7 +727,7 @@ HTTPs 的报文摘要功能之所以安全,是因为它结合了加密和认 ## HTTP/1.x 缺陷 - HTTP/1.x 实现简单是以牺牲应用性能为代价的: + HTTP/1.x 实现简单是以牺牲性能为代价的: - 客户端需要使用多个连接才能实现并发和缩短延迟; - 不会压缩请求和响应首部,从而导致不必要的网络流量; @@ -763,7 +763,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见

-# 八、GET 和 POST 的区别 +# 八、GET 和 POST 比较 ## 作用 @@ -870,6 +870,7 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404 - [MDN : HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP) - [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn) - [htmlspecialchars](http://php.net/manual/zh/function.htmlspecialchars.php) +- [Difference between file URI and URL in java](http://java2db.com/java-io/how-to-get-and-the-difference-between-file-uri-and-url-in-java) - [How to Fix SQL Injection Using Java PreparedStatement & CallableStatement](https://software-security.sans.org/developer-how-to/fix-sql-injection-in-java-using-prepared-callable-statement) - [浅谈 HTTP 中 Get 与 Post 的区别](https://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html) - [Are http:// and www really necessary?](https://www.webdancers.com/are-http-and-www-necesary/) diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index 293f4328..102fe9b6 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -33,10 +33,6 @@ * [多数投票问题](#多数投票问题) * [其它](#其它) * [数据结构相关](#数据结构相关) - * [栈和队列](#栈和队列) - * [哈希表](#哈希表) - * [字符串](#字符串) - * [数组与矩阵](#数组与矩阵) * [链表](#链表) * [树](#树) * [递归](#递归) @@ -44,6 +40,10 @@ * [前中后序遍历](#前中后序遍历) * [BST](#bst) * [Trie](#trie) + * [栈和队列](#栈和队列) + * [哈希表](#哈希表) + * [字符串](#字符串) + * [数组与矩阵](#数组与矩阵) * [图](#图) * [二分图](#二分图) * [拓扑排序](#拓扑排序) @@ -2371,7 +2371,9 @@ public List diffWaysToCompute(String input) { 题目描述:有 N 阶楼梯,每次可以上一阶或者两阶,求有多少种上楼梯的方法。 -定义一个数组 dp 存储上楼梯的方法数(为了方便讨论,数组下标从 1 开始),dp[i] 表示走到第 i 个楼梯的方法数目。第 i 个楼梯可以从第 i-1 和 i-2 个楼梯再走一步到达,走到第 i 个楼梯的方法数为走到第 i-1 和第 i-2 个楼梯的方法数之和。 +定义一个数组 dp 存储上楼梯的方法数(为了方便讨论,数组下标从 1 开始),dp[i] 表示走到第 i 个楼梯的方法数目。 + +第 i 个楼梯可以从第 i-1 和 i-2 个楼梯再走一步到达,走到第 i 个楼梯的方法数为走到第 i-1 和第 i-2 个楼梯的方法数之和。

@@ -2400,7 +2402,9 @@ public int climbStairs(int n) { 题目描述:抢劫一排住户,但是不能抢邻近的住户,求最大抢劫量。 -定义 dp 数组用来存储最大的抢劫量,其中 dp[i] 表示抢到第 i 个住户时的最大抢劫量。由于不能抢劫邻近住户,因此如果抢劫了第 i 个住户那么只能抢劫 i - 2 或者 i - 3 的住户,所以 +定义 dp 数组用来存储最大的抢劫量,其中 dp[i] 表示抢到第 i 个住户时的最大抢劫量。 + +由于不能抢劫邻近住户,因此如果抢劫了第 i 个住户那么只能抢劫 i - 2 或者 i - 3 的住户,所以

@@ -4032,973 +4036,6 @@ public int maximumProduct(int[] nums) { # 数据结构相关 -## 栈和队列 - -**用栈实现队列** - -[232. Implement Queue using Stacks (Easy)](https://leetcode.com/problems/implement-queue-using-stacks/description/) - -```java -class MyQueue { - - private Stack in = new Stack<>(); - private Stack out = new Stack<>(); - - public void push(int x) { - in.push(x); - } - - public int pop() { - in2out(); - return out.pop(); - } - - public int peek() { - in2out(); - return out.peek(); - } - - private void in2out() { - if (out.isEmpty()) { - while (!in.isEmpty()) { - out.push(in.pop()); - } - } - } - - public boolean empty() { - return in.isEmpty() && out.isEmpty(); - } -} -``` - -**用队列实现栈** - -[225. Implement Stack using Queues (Easy)](https://leetcode.com/problems/implement-stack-using-queues/description/) - -在将一个元素 x 插入队列时,需要让除了 x 之外的所有元素出队列,再入队列。此时 x 在队首,第一个出队列,实现了后进先出顺序。 - -```java -class MyStack { - - private Queue queue; - - public MyStack() { - queue = new LinkedList<>(); - } - - public void push(int x) { - queue.add(x); - int cnt = queue.size(); - while (cnt-- > 1) { - queue.add(queue.poll()); - } - } - - public int pop() { - return queue.remove(); - } - - public int top() { - return queue.peek(); - } - - public boolean empty() { - return queue.isEmpty(); - } -} -``` - -**最小值栈** - -[155. Min Stack (Easy)](https://leetcode.com/problems/min-stack/description/) - -```java -class MinStack { - - private Stack dataStack; - private Stack minStack; - private int min; - - public MinStack() { - dataStack = new Stack<>(); - minStack = new Stack<>(); - min = Integer.MAX_VALUE; - } - - public void push(int x) { - dataStack.add(x); - min = Math.min(min, x); - minStack.add(min); - } - - public void pop() { - dataStack.pop(); - minStack.pop(); - min = minStack.isEmpty() ? Integer.MAX_VALUE : minStack.peek(); - } - - public int top() { - return dataStack.peek(); - } - - public int getMin() { - return minStack.peek(); - } -} -``` - -对于实现最小值队列问题,可以先将队列使用栈来实现,然后就将问题转换为最小值栈,这个问题出现在 编程之美:3.7。 - -**用栈实现括号匹配** - -[20. Valid Parentheses (Easy)](https://leetcode.com/problems/valid-parentheses/description/) - -```html -"()[]{}" - -Output : true -``` - -```java -public boolean isValid(String s) { - Stack stack = new Stack<>(); - for (char c : s.toCharArray()) { - if (c == '(' || c == '{' || c == '[') { - stack.push(c); - } else { - if (stack.isEmpty()) { - return false; - } - char cStack = stack.pop(); - boolean b1 = c == ')' && cStack != '('; - boolean b2 = c == ']' && cStack != '['; - boolean b3 = c == '}' && cStack != '{'; - if (b1 || b2 || b3) { - return false; - } - } - } - return stack.isEmpty(); -} -``` - -**数组中元素与下一个比它大的元素之间的距离** - -[739. Daily Temperatures (Medium)](https://leetcode.com/problems/daily-temperatures/description/) - -```html -Input: [73, 74, 75, 71, 69, 72, 76, 73] -Output: [1, 1, 4, 2, 1, 1, 0, 0] -``` - -在遍历数组时用 Stack 把数组中的数存起来,如果当前遍历的数比栈顶元素来的大,说明栈顶元素的下一个比它大的数就是当前元素。 - -```java -public int[] dailyTemperatures(int[] temperatures) { - int n = temperatures.length; - int[] dist = new int[n]; - Stack indexs = new Stack<>(); - for (int curIndex = 0; curIndex < n; curIndex++) { - while (!indexs.isEmpty() && temperatures[curIndex] > temperatures[indexs.peek()]) { - int preIndex = indexs.pop(); - dist[preIndex] = curIndex - preIndex; - } - indexs.add(curIndex); - } - return dist; -} -``` - -**循环数组中比当前元素大的下一个元素** - -[503. Next Greater Element II (Medium)](https://leetcode.com/problems/next-greater-element-ii/description/) - -```text -Input: [1,2,1] -Output: [2,-1,2] -Explanation: The first 1's next greater number is 2; -The number 2 can't find next greater number; -The second 1's next greater number needs to search circularly, which is also 2. -``` - -与 739. Daily Temperatures (Medium) 不同的是,数组是循环数组,并且最后要求的不是距离而是下一个元素。 - -```java -public int[] nextGreaterElements(int[] nums) { - int n = nums.length; - int[] next = new int[n]; - Arrays.fill(next, -1); - Stack pre = new Stack<>(); - for (int i = 0; i < n * 2; i++) { - int num = nums[i % n]; - while (!pre.isEmpty() && nums[pre.peek()] < num) { - next[pre.pop()] = num; - } - if (i < n){ - pre.push(i); - } - } - return next; -} -``` - -## 哈希表 - -哈希表使用 O(N) 空间复杂度存储数据,从而能够以 O(1) 时间复杂度求解问题。 - -Java 中的 **HashSet** 用于存储一个集合,可以查找元素是否在集合中。 - -如果元素有穷,并且范围不大,那么可以用一个布尔数组来存储一个元素是否存在。例如对于只有小写字符的元素,就可以用一个长度为 26 的布尔数组来存储一个字符集合,使得空间复杂度降低为 O(1)。 - -Java 中的 **HashMap** 主要用于映射关系,从而把两个元素联系起来。 - -在对一个内容进行压缩或者其它转换时,利用 HashMap 可以把原始内容和转换后的内容联系起来。例如在一个简化 url 的系统中[Leetcdoe : 535. Encode and Decode TinyURL (Medium)](https://leetcode.com/problems/encode-and-decode-tinyurl/description/),利用 HashMap 就可以存储精简后的 url 到原始 url 的映射,使得不仅可以显示简化的 url,也可以根据简化的 url 得到原始 url 从而定位到正确的资源。 - -HashMap 也可以用来对元素进行计数统计,此时键为元素,值为计数。和 HashSet 类似,如果元素有穷并且范围不大,可以用整型数组来进行统计。 - -**数组中的两个数和为给定值** - -[1. Two Sum (Easy)](https://leetcode.com/problems/two-sum/description/) - -可以先对数组进行排序,然后使用双指针方法或者二分查找方法。这样做的时间复杂度为 O(NlogN),空间复杂度为 O(1)。 - -用 HashMap 存储数组元素和索引的映射,在访问到 nums[i] 时,判断 HashMap 中是否存在 target - nums[i],如果存在说明 target - nums[i] 所在的索引和 i 就是要找的两个数。该方法的时间复杂度为 O(N),空间复杂度为 O(N),使用空间来换取时间。 - -```java -public int[] twoSum(int[] nums, int target) { - HashMap indexForNum = new HashMap<>(); - for (int i = 0; i < nums.length; i++) { - if (indexForNum.containsKey(target - nums[i])) { - return new int[]{indexForNum.get(target - nums[i]), i}; - } else { - indexForNum.put(nums[i], i); - } - } - return null; -} -``` - -**判断数组是否含有重复元素** - -[217. Contains Duplicate (Easy)](https://leetcode.com/problems/contains-duplicate/description/) - -```java -public boolean containsDuplicate(int[] nums) { - Set set = new HashSet<>(); - for (int num : nums) { - set.add(num); - } - return set.size() < nums.length; -} -``` - -**最长和谐序列** - -[594. Longest Harmonious Subsequence (Easy)](https://leetcode.com/problems/longest-harmonious-subsequence/description/) - -```html -Input: [1,3,2,2,5,2,3,7] -Output: 5 -Explanation: The longest harmonious subsequence is [3,2,2,2,3]. -``` - -和谐序列中最大数和最小数只差正好为 1,应该注意的是序列的元素不一定是数组的连续元素。 - -```java -public int findLHS(int[] nums) { - Map countForNum = new HashMap<>(); - for (int num : nums) { - countForNum.put(num, countForNum.getOrDefault(num, 0) + 1); - } - int longest = 0; - for (int num : countForNum.keySet()) { - if (countForNum.containsKey(num + 1)) { - longest = Math.max(longest, countForNum.get(num + 1) + countForNum.get(num)); - } - } - return longest; -} -``` - -**最长连续序列** - -[128. Longest Consecutive Sequence (Hard)](https://leetcode.com/problems/longest-consecutive-sequence/description/) - -```html -Given [100, 4, 200, 1, 3, 2], -The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. -``` - -要求以 O(N) 的时间复杂度求解。 - -```java -public int longestConsecutive(int[] nums) { - Map countForNum = new HashMap<>(); - for (int num : nums) { - countForNum.put(num, 1); - } - for (int num : nums) { - forward(countForNum, num); - } - return maxCount(countForNum); -} - -private int forward(Map countForNum, int num) { - if (!countForNum.containsKey(num)) { - return 0; - } - int cnt = countForNum.get(num); - if (cnt > 1) { - return cnt; - } - cnt = forward(countForNum, num + 1) + 1; - countForNum.put(num, cnt); - return cnt; -} - -private int maxCount(Map countForNum) { - int max = 0; - for (int num : countForNum.keySet()) { - max = Math.max(max, countForNum.get(num)); - } - return max; -} -``` - -## 字符串 - -**两个字符串包含的字符是否完全相同** - -[242. Valid Anagram (Easy)](https://leetcode.com/problems/valid-anagram/description/) - -```html -s = "anagram", t = "nagaram", return true. -s = "rat", t = "car", return false. -``` - -字符串只包含小写字符,总共有 26 个小写字符。可以用 HashMap 来映射字符与出现次数。因为键的范围很小,因此可以使用长度为 26 的整型数组对字符串出现的字符进行统计,然后比较两个字符串出现的字符数量是否相同。 - -```java -public boolean isAnagram(String s, String t) { - int[] cnts = new int[26]; - for (char c : s.toCharArray()) { - cnts[c - 'a']++; - } - for (char c : t.toCharArray()) { - cnts[c - 'a']--; - } - for (int cnt : cnts) { - if (cnt != 0) { - return false; - } - } - return true; -} -``` - -**计算一组字符集合可以组成的回文字符串的最大长度** - -[409. Longest Palindrome (Easy)](https://leetcode.com/problems/longest-palindrome/description/) - -```html -Input : "abccccdd" -Output : 7 -Explanation : One longest palindrome that can be built is "dccaccd", whose length is 7. -``` - -使用长度为 256 的整型数组来统计每个字符出现的个数,每个字符有偶数个可以用来构成回文字符串。 - -因为回文字符串最中间的那个字符可以单独出现,所以如果有单独的字符就把它放到最中间。 - -```java -public int longestPalindrome(String s) { - int[] cnts = new int[256]; - for (char c : s.toCharArray()) { - cnts[c]++; - } - int palindrome = 0; - for (int cnt : cnts) { - palindrome += (cnt / 2) * 2; - } - if (palindrome < s.length()) { - palindrome++; // 这个条件下 s 中一定有单个未使用的字符存在,可以把这个字符放到回文的最中间 - } - return palindrome; -} -``` - -**字符串同构** - -[205. Isomorphic Strings (Easy)](https://leetcode.com/problems/isomorphic-strings/description/) - -```html -Given "egg", "add", return true. -Given "foo", "bar", return false. -Given "paper", "title", return true. -``` - -记录一个字符上次出现的位置,如果两个字符串中的字符上次出现的位置一样,那么就属于同构。 - -```java -public boolean isIsomorphic(String s, String t) { - int[] preIndexOfS = new int[256]; - int[] preIndexOfT = new int[256]; - for (int i = 0; i < s.length(); i++) { - char sc = s.charAt(i), tc = t.charAt(i); - if (preIndexOfS[sc] != preIndexOfT[tc]) { - return false; - } - preIndexOfS[sc] = i + 1; - preIndexOfT[tc] = i + 1; - } - return true; -} -``` - -**回文子字符串** - -[647. Palindromic Substrings (Medium)](https://leetcode.com/problems/palindromic-substrings/description/) - -```html -Input: "aaa" -Output: 6 -Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa". -``` - -从字符串的某一位开始,尝试着去扩展子字符串。 - -```java -private int cnt = 0; - -public int countSubstrings(String s) { - for (int i = 0; i < s.length(); i++) { - extendSubstrings(s, i, i); // 奇数长度 - extendSubstrings(s, i, i + 1); // 偶数长度 - } - return cnt; -} - -private void extendSubstrings(String s, int start, int end) { - while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) { - start--; - end++; - cnt++; - } -} -``` - -**判断一个整数是否是回文数** - -[9. Palindrome Number (Easy)](https://leetcode.com/problems/palindrome-number/description/) - -要求不能使用额外空间,也就不能将整数转换为字符串进行判断。 - -将整数分成左右两部分,右边那部分需要转置,然后判断这两部分是否相等。 - -```java -public boolean isPalindrome(int x) { - if (x == 0) { - return true; - } - if (x < 0 || x % 10 == 0) { - return false; - } - int right = 0; - while (x > right) { - right = right * 10 + x % 10; - x /= 10; - } - return x == right || x == right / 10; -} -``` - -**统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数** - -[696. Count Binary Substrings (Easy)](https://leetcode.com/problems/count-binary-substrings/description/) - -```html -Input: "00110011" -Output: 6 -Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: "0011", "01", "1100", "10", "0011", and "01". -``` - -```java -public int countBinarySubstrings(String s) { - int preLen = 0, curLen = 1, count = 0; - for (int i = 1; i < s.length(); i++) { - if (s.charAt(i) == s.charAt(i - 1)) { - curLen++; - } else { - preLen = curLen; - curLen = 1; - } - - if (preLen >= curLen) { - count++; - } - } - return count; -} -``` - -**字符串循环移位包含** - -[编程之美:3.1](#) - -```html -s1 = AABCD, s2 = CDAA -Return : true -``` - -给定两个字符串 s1 和 s2,要求判定 s2 是否能够被 s1 做循环移位得到的字符串包含。 - -s1 进行循环移位的结果是 s1s1 的子字符串,因此只要判断 s2 是否是 s1s1 的子字符串即可。 - -**字符串循环移位** - -[编程之美:2.17](#) - -```html -s = "abcd123" k = 3 -Return "123abcd" -``` - -将字符串向右循环移动 k 位。 - -将 abcd123 中的 abcd 和 123 单独逆序,得到 dcba321,然后对整个字符串进行逆序,得到 123abcd。 - -**字符串中单词的翻转** - -[程序员代码面试指南](#) - -```html -s = "I am a student" -return "student a am I" -``` - -将每个单词逆序,然后将整个字符串逆序。 - -## 数组与矩阵 - -**把数组中的 0 移到末尾** - -[283. Move Zeroes (Easy)](https://leetcode.com/problems/move-zeroes/description/) - -```html -For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. -``` - -```java -public void moveZeroes(int[] nums) { - int idx = 0; - for (int num : nums) { - if (num != 0) { - nums[idx++] = num; - } - } - while (idx < nums.length) { - nums[idx++] = 0; - } -} -``` - -**改变矩阵维度** - -[566. Reshape the Matrix (Easy)](https://leetcode.com/problems/reshape-the-matrix/description/) - -```html -Input: -nums = -[[1,2], - [3,4]] -r = 1, c = 4 - -Output: -[[1,2,3,4]] - -Explanation: -The row-traversing of nums is [1,2,3,4]. The new reshaped matrix is a 1 * 4 matrix, fill it row by row by using the previous list. -``` - -```java -public int[][] matrixReshape(int[][] nums, int r, int c) { - int m = nums.length, n = nums[0].length; - if (m * n != r * c) { - return nums; - } - int[][] reshapedNums = new int[r][c]; - int index = 0; - for (int i = 0; i < r; i++) { - for (int j = 0; j < c; j++) { - reshapedNums[i][j] = nums[index / n][index % n]; - index++; - } - } - return reshapedNums; -} -``` - -**找出数组中最长的连续 1** - -[485. Max Consecutive Ones (Easy)](https://leetcode.com/problems/max-consecutive-ones/description/) - -```java -public int findMaxConsecutiveOnes(int[] nums) { - int max = 0, cur = 0; - for (int x : nums) { - cur = x == 0 ? 0 : cur + 1; - max = Math.max(max, cur); - } - return max; -} -``` - -**一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数** - -[645. Set Mismatch (Easy)](https://leetcode.com/problems/set-mismatch/description/) - -```html -Input: nums = [1,2,2,4] -Output: [2,3] -``` - -```html -Input: nums = [1,2,2,4] -Output: [2,3] -``` - -最直接的方法是先对数组进行排序,这种方法时间复杂度为 O(NlogN)。本题可以以 O(N) 的时间复杂度、O(1) 空间复杂度来求解。 - -主要思想是通过交换数组元素,使得数组上的元素在正确的位置上。遍历数组,如果第 i 位上的元素不是 i + 1,那么一直交换第 i 位和 nums[i] - 1 位置上的元素。 - -```java -public int[] findErrorNums(int[] nums) { - for (int i = 0; i < nums.length; i++) { - while (nums[i] != i + 1 && nums[nums[i] - 1] != nums[i]) { - swap(nums, i, nums[i] - 1); - } - } - for (int i = 0; i < nums.length; i++) { - if (nums[i] != i + 1) { - return new int[]{nums[i], i + 1}; - } - } - return null; -} - -private void swap(int[] nums, int i, int j) { - int tmp = nums[i]; - nums[i] = nums[j]; - nums[j] = tmp; -} -``` - -类似题目: - -- [448. Find All Numbers Disappeared in an Array (Easy)](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/),寻找所有丢失的元素 -- [442. Find All Duplicates in an Array (Medium)](https://leetcode.com/problems/find-all-duplicates-in-an-array/description/),寻找所有重复的元素。 - -**找出数组中重复的数,数组值在 [1, n] 之间** - -[287. Find the Duplicate Number (Medium)](https://leetcode.com/problems/find-the-duplicate-number/description/) - -要求不能修改数组,也不能使用额外的空间。 - -二分查找解法: - -```java -public int findDuplicate(int[] nums) { - int l = 1, h = nums.length - 1; - while (l <= h) { - int mid = l + (h - l) / 2; - int cnt = 0; - for (int i = 0; i < nums.length; i++) { - if (nums[i] <= mid) cnt++; - } - if (cnt > mid) h = mid - 1; - else l = mid + 1; - } - return l; -} -``` - -双指针解法,类似于有环链表中找出环的入口: - -```java -public int findDuplicate(int[] nums) { - int slow = nums[0], fast = nums[nums[0]]; - while (slow != fast) { - slow = nums[slow]; - fast = nums[nums[fast]]; - } - fast = 0; - while (slow != fast) { - slow = nums[slow]; - fast = nums[fast]; - } - return slow; -} -``` - -**有序矩阵查找** - -[240. Search a 2D Matrix II (Medium)](https://leetcode.com/problems/search-a-2d-matrix-ii/description/) - -```html -[ - [ 1, 5, 9], - [10, 11, 13], - [12, 13, 15] -] -``` - -```java -public boolean searchMatrix(int[][] matrix, int target) { - if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false; - int m = matrix.length, n = matrix[0].length; - int row = 0, col = n - 1; - while (row < m && col >= 0) { - if (target == matrix[row][col]) return true; - else if (target < matrix[row][col]) col--; - else row++; - } - return false; -} -``` - -**有序矩阵的 Kth Element** - -[378. Kth Smallest Element in a Sorted Matrix ((Medium))](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/description/) - -```html -matrix = [ - [ 1, 5, 9], - [10, 11, 13], - [12, 13, 15] -], -k = 8, - -return 13. -``` - -解题参考:[Share my thoughts and Clean Java Code](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/discuss/85173) - -二分查找解法: - -```java -public int kthSmallest(int[][] matrix, int k) { - int m = matrix.length, n = matrix[0].length; - int lo = matrix[0][0], hi = matrix[m - 1][n - 1]; - while(lo <= hi) { - int mid = lo + (hi - lo) / 2; - int cnt = 0; - for(int i = 0; i < m; i++) { - for(int j = 0; j < n && matrix[i][j] <= mid; j++) { - cnt++; - } - } - if(cnt < k) lo = mid + 1; - else hi = mid - 1; - } - return lo; -} -``` - -堆解法: - -```java -public int kthSmallest(int[][] matrix, int k) { - int m = matrix.length, n = matrix[0].length; - PriorityQueue pq = new PriorityQueue(); - for(int j = 0; j < n; j++) pq.offer(new Tuple(0, j, matrix[0][j])); - for(int i = 0; i < k - 1; i++) { // 小根堆,去掉 k - 1 个堆顶元素,此时堆顶元素就是第 k 的数 - Tuple t = pq.poll(); - if(t.x == m - 1) continue; - pq.offer(new Tuple(t.x + 1, t.y, matrix[t.x + 1][t.y])); - } - return pq.poll().val; -} - -class Tuple implements Comparable { - int x, y, val; - public Tuple(int x, int y, int val) { - this.x = x; this.y = y; this.val = val; - } - - @Override - public int compareTo(Tuple that) { - return this.val - that.val; - } -} -``` - -**数组相邻差值的个数** - -[667. Beautiful Arrangement II (Medium)](https://leetcode.com/problems/beautiful-arrangement-ii/description/) - -```html -Input: n = 3, k = 2 -Output: [1, 3, 2] -Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2. -``` - -题目描述:数组元素为 1\~n 的整数,要求构建数组,使得相邻元素的差值不相同的个数为 k。 - -让前 k+1 个元素构建出 k 个不相同的差值,序列为:1 k+1 2 k 3 k-1 ... k/2 k/2+1. - -```java -public int[] constructArray(int n, int k) { - int[] ret = new int[n]; - ret[0] = 1; - for (int i = 1, interval = k; i <= k; i++, interval--) { - ret[i] = i % 2 == 1 ? ret[i - 1] + interval : ret[i - 1] - interval; - } - for (int i = k + 1; i < n; i++) { - ret[i] = i + 1; - } - return ret; -} -``` - -**数组的度** - -[697. Degree of an Array (Easy)](https://leetcode.com/problems/degree-of-an-array/description/) - -```html -Input: [1,2,2,3,1,4,2] -Output: 6 -``` - -题目描述:数组的度定义为元素出现的最高频率,例如上面的数组度为 3。要求找到一个最小的子数组,这个子数组的度和原数组一样。 - -```java -public int findShortestSubArray(int[] nums) { - Map numsCnt = new HashMap<>(); - Map numsLastIndex = new HashMap<>(); - Map numsFirstIndex = new HashMap<>(); - for (int i = 0; i < nums.length; i++) { - int num = nums[i]; - numsCnt.put(num, numsCnt.getOrDefault(num, 0) + 1); - numsLastIndex.put(num, i); - if (!numsFirstIndex.containsKey(num)) { - numsFirstIndex.put(num, i); - } - } - int maxCnt = 0; - for (int num : nums) { - maxCnt = Math.max(maxCnt, numsCnt.get(num)); - } - int ret = nums.length; - for (int i = 0; i < nums.length; i++) { - int num = nums[i]; - int cnt = numsCnt.get(num); - if (cnt != maxCnt) continue; - ret = Math.min(ret, numsLastIndex.get(num) - numsFirstIndex.get(num) + 1); - } - return ret; -} -``` - -**对角元素相等的矩阵** - -[766. Toeplitz Matrix (Easy)](https://leetcode.com/problems/toeplitz-matrix/description/) - -```html -1234 -5123 -9512 - -In the above grid, the diagonals are "[9]", "[5, 5]", "[1, 1, 1]", "[2, 2, 2]", "[3, 3]", "[4]", and in each diagonal all elements are the same, so the answer is True. -``` - -```java -public boolean isToeplitzMatrix(int[][] matrix) { - for (int i = 0; i < matrix[0].length; i++) { - if (!check(matrix, matrix[0][i], 0, i)) { - return false; - } - } - for (int i = 0; i < matrix.length; i++) { - if (!check(matrix, matrix[i][0], i, 0)) { - return false; - } - } - return true; -} - -private boolean check(int[][] matrix, int expectValue, int row, int col) { - if (row >= matrix.length || col >= matrix[0].length) { - return true; - } - if (matrix[row][col] != expectValue) { - return false; - } - return check(matrix, expectValue, row + 1, col + 1); -} -``` - -**嵌套数组** - -[565. Array Nesting (Medium)](https://leetcode.com/problems/array-nesting/description/) - -```html -Input: A = [5,4,0,3,1,6,2] -Output: 4 -Explanation: -A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2. - -One of the longest S[K]: -S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0} -``` - -题目描述:S[i] 表示一个集合,集合的第一个元素是 A[i],第二个元素是 A[A[i]],如此嵌套下去。求最大的 S[i]。 - -```java -public int arrayNesting(int[] nums) { - int max = 0; - for (int i = 0; i < nums.length; i++) { - int cnt = 0; - for (int j = i; nums[j] != -1; ) { - cnt++; - int t = nums[j]; - nums[j] = -1; // 标记该位置已经被访问 - j = t; - - } - max = Math.max(max, cnt); - } - return max; -} -``` - -**分隔数组** - -[769. Max Chunks To Make Sorted (Medium)](https://leetcode.com/problems/max-chunks-to-make-sorted/description/) - -```html -Input: arr = [1,0,2,3,4] -Output: 4 -Explanation: -We can split into two chunks, such as [1, 0], [2, 3, 4]. -However, splitting into [1, 0], [2], [3], [4] is the highest number of chunks possible. -``` - -题目描述:分隔数组,使得对每部分排序后数组就为有序。 - -```java -public int maxChunksToSorted(int[] arr) { - if (arr == null) return 0; - int ret = 0; - int right = arr[0]; - for (int i = 0; i < arr.length; i++) { - right = Math.max(right, arr[i]); - if (right == i) ret++; - } - return ret; -} -``` - ## 链表 链表是空节点,或者有一个值和一个指向下一个链表的指针,因此很多链表问题可以用递归来处理。 @@ -5032,7 +4069,10 @@ public ListNode getIntersectionNode(ListNode headA, ListNode headB) { } ``` -如果只是判断是否存在交点,那么就是另一个问题,即 [编程之美:3.6]() 的问题。有两种解法:把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;或者直接比较两个链表的最后一个节点是否相同。 +如果只是判断是否存在交点,那么就是另一个问题,即 [编程之美 3.6]() 的问题。有两种解法: + +- 把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环; +- 或者直接比较两个链表的最后一个节点是否相同。 **链表反转** @@ -5097,7 +4137,7 @@ Given 1->1->2->3->3, return 1->2->3. ```java public ListNode deleteDuplicates(ListNode head) { - if(head == null || head.next == null) return head; + if (head == null || head.next == null) return head; head.next = deleteDuplicates(head.next); return head.val == head.next.val ? head.next : head; } @@ -5419,8 +4459,8 @@ Input: 3 2 1 3 / \ \ 5 4 7 + Output: -Merged tree: 3 / \ 4 5 @@ -5446,6 +4486,7 @@ public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { ```html Given the below binary tree and sum = 22, + 5 / \ 4 8 @@ -5453,10 +4494,11 @@ Given the below binary tree and sum = 22, 11 13 4 / \ \ 7 2 1 + return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. ``` -路径和定义为从 root 到 leaf 的所有节点的和 +路径和定义为从 root 到 leaf 的所有节点的和。 ```java public boolean hasPathSum(TreeNode root, int sum) { @@ -5848,7 +4890,7 @@ public List preorderTraversal(TreeNode root) { [145. Binary Tree Postorder Traversal (Medium)](https://leetcode.com/problems/binary-tree-postorder-traversal/description/) -前序遍历为 root -> left -> right,后序遍历为 left -> right -> root,可以修改前序遍历成为 root -> right -> left,那么这个顺序就和后序遍历正好相反。 +前序遍历为 root -> left -> right,后序遍历为 left -> right -> root。可以修改前序遍历成为 root -> right -> left,那么这个顺序就和后序遍历正好相反。 ```java public List postorderTraversal(TreeNode root) { @@ -6106,7 +5148,7 @@ public TreeNode sortedListToBST(ListNode head) { if (head == null) return null; if (head.next == null) return new TreeNode(head.val); ListNode preMid = preMid(head); - ListNode mid = preMid.next; + ListNode mid = preMid.next; preMid.next = null; // 断开链表 TreeNode t = new TreeNode(mid.val); t.left = sortedListToBST(head); @@ -6222,7 +5264,7 @@ private void inOrder(TreeNode node) { return [2]. ``` -答案可能不止一个,也就是有多个值出现的次数一样多,并且是最大的。 +答案可能不止一个,也就是有多个值出现的次数一样多。 ```java private int curCnt = 1; @@ -6392,6 +5434,974 @@ class MapSum { } ``` + +## 栈和队列 + +**用栈实现队列** + +[232. Implement Queue using Stacks (Easy)](https://leetcode.com/problems/implement-queue-using-stacks/description/) + +栈的顺序为后进先出,而队列的顺序为先进先出。使用两个栈实现队列,一个元素需要经过两个栈才能出队列,在经过第一个栈时元素顺序被反转,经过第二个栈时再次被反转,此时就是先进先出顺序。 + +```java +class MyQueue { + + private Stack in = new Stack<>(); + private Stack out = new Stack<>(); + + public void push(int x) { + in.push(x); + } + + public int pop() { + in2out(); + return out.pop(); + } + + public int peek() { + in2out(); + return out.peek(); + } + + private void in2out() { + if (out.isEmpty()) { + while (!in.isEmpty()) { + out.push(in.pop()); + } + } + } + + public boolean empty() { + return in.isEmpty() && out.isEmpty(); + } +} +``` + +**用队列实现栈** + +[225. Implement Stack using Queues (Easy)](https://leetcode.com/problems/implement-stack-using-queues/description/) + +在将一个元素 x 插入队列时,为了维护原来的后进先出顺序,需要让 x 插入队列首部。而队列的默认插入顺序是队列尾部,因此在将 x 插入队列尾部之后,需要让除了 x 之外的所有元素出队列,再入队列。 + +```java +class MyStack { + + private Queue queue; + + public MyStack() { + queue = new LinkedList<>(); + } + + public void push(int x) { + queue.add(x); + int cnt = queue.size(); + while (cnt-- > 1) { + queue.add(queue.poll()); + } + } + + public int pop() { + return queue.remove(); + } + + public int top() { + return queue.peek(); + } + + public boolean empty() { + return queue.isEmpty(); + } +} +``` + +**最小值栈** + +[155. Min Stack (Easy)](https://leetcode.com/problems/min-stack/description/) + +```java +class MinStack { + + private Stack dataStack; + private Stack minStack; + private int min; + + public MinStack() { + dataStack = new Stack<>(); + minStack = new Stack<>(); + min = Integer.MAX_VALUE; + } + + public void push(int x) { + dataStack.add(x); + min = Math.min(min, x); + minStack.add(min); + } + + public void pop() { + dataStack.pop(); + minStack.pop(); + min = minStack.isEmpty() ? Integer.MAX_VALUE : minStack.peek(); + } + + public int top() { + return dataStack.peek(); + } + + public int getMin() { + return minStack.peek(); + } +} +``` + +对于实现最小值队列问题,可以先将队列使用栈来实现,然后就将问题转换为最小值栈,这个问题出现在 编程之美:3.7。 + +**用栈实现括号匹配** + +[20. Valid Parentheses (Easy)](https://leetcode.com/problems/valid-parentheses/description/) + +```html +"()[]{}" + +Output : true +``` + +```java +public boolean isValid(String s) { + Stack stack = new Stack<>(); + for (char c : s.toCharArray()) { + if (c == '(' || c == '{' || c == '[') { + stack.push(c); + } else { + if (stack.isEmpty()) { + return false; + } + char cStack = stack.pop(); + boolean b1 = c == ')' && cStack != '('; + boolean b2 = c == ']' && cStack != '['; + boolean b3 = c == '}' && cStack != '{'; + if (b1 || b2 || b3) { + return false; + } + } + } + return stack.isEmpty(); +} +``` + +**数组中元素与下一个比它大的元素之间的距离** + +[739. Daily Temperatures (Medium)](https://leetcode.com/problems/daily-temperatures/description/) + +```html +Input: [73, 74, 75, 71, 69, 72, 76, 73] +Output: [1, 1, 4, 2, 1, 1, 0, 0] +``` + +在遍历数组时用栈把数组中的数存起来,如果当前遍历的数比栈顶元素来的大,说明栈顶元素的下一个比它大的数就是当前元素。 + +```java +public int[] dailyTemperatures(int[] temperatures) { + int n = temperatures.length; + int[] dist = new int[n]; + Stack indexs = new Stack<>(); + for (int curIndex = 0; curIndex < n; curIndex++) { + while (!indexs.isEmpty() && temperatures[curIndex] > temperatures[indexs.peek()]) { + int preIndex = indexs.pop(); + dist[preIndex] = curIndex - preIndex; + } + indexs.add(curIndex); + } + return dist; +} +``` + +**循环数组中比当前元素大的下一个元素** + +[503. Next Greater Element II (Medium)](https://leetcode.com/problems/next-greater-element-ii/description/) + +```text +Input: [1,2,1] +Output: [2,-1,2] +Explanation: The first 1's next greater number is 2; +The number 2 can't find next greater number; +The second 1's next greater number needs to search circularly, which is also 2. +``` + +与 739. Daily Temperatures (Medium) 不同的是,数组是循环数组,并且最后要求的不是距离而是下一个元素。 + +```java +public int[] nextGreaterElements(int[] nums) { + int n = nums.length; + int[] next = new int[n]; + Arrays.fill(next, -1); + Stack pre = new Stack<>(); + for (int i = 0; i < n * 2; i++) { + int num = nums[i % n]; + while (!pre.isEmpty() && nums[pre.peek()] < num) { + next[pre.pop()] = num; + } + if (i < n){ + pre.push(i); + } + } + return next; +} +``` + +## 哈希表 + +哈希表使用 O(N) 空间复杂度存储数据,并且以 O(1) 时间复杂度求解问题。 + +- Java 中的 **HashSet** 用于存储一个集合,可以查找元素是否在集合中。如果元素有穷,并且范围不大,那么可以用一个布尔数组来存储一个元素是否存在。例如对于只有小写字符的元素,就可以用一个长度为 26 的布尔数组来存储一个字符集合,使得空间复杂度降低为 O(1)。 + +- Java 中的 **HashMap** 主要用于映射关系,从而把两个元素联系起来。HashMap 也可以用来对元素进行计数统计,此时键为元素,值为计数。和 HashSet 类似,如果元素有穷并且范围不大,可以用整型数组来进行统计。在对一个内容进行压缩或者其它转换时,利用 HashMap 可以把原始内容和转换后的内容联系起来。例如在一个简化 url 的系统中 [Leetcdoe : 535. Encode and Decode TinyURL (Medium)](https://leetcode.com/problems/encode-and-decode-tinyurl/description/),利用 HashMap 就可以存储精简后的 url 到原始 url 的映射,使得不仅可以显示简化的 url,也可以根据简化的 url 得到原始 url 从而定位到正确的资源。 + + +**数组中两个数的和为给定值** + +[1. Two Sum (Easy)](https://leetcode.com/problems/two-sum/description/) + +可以先对数组进行排序,然后使用双指针方法或者二分查找方法。这样做的时间复杂度为 O(NlogN),空间复杂度为 O(1)。 + +用 HashMap 存储数组元素和索引的映射,在访问到 nums[i] 时,判断 HashMap 中是否存在 target - nums[i],如果存在说明 target - nums[i] 所在的索引和 i 就是要找的两个数。该方法的时间复杂度为 O(N),空间复杂度为 O(N),使用空间来换取时间。 + +```java +public int[] twoSum(int[] nums, int target) { + HashMap indexForNum = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + if (indexForNum.containsKey(target - nums[i])) { + return new int[]{indexForNum.get(target - nums[i]), i}; + } else { + indexForNum.put(nums[i], i); + } + } + return null; +} +``` + +**判断数组是否含有重复元素** + +[217. Contains Duplicate (Easy)](https://leetcode.com/problems/contains-duplicate/description/) + +```java +public boolean containsDuplicate(int[] nums) { + Set set = new HashSet<>(); + for (int num : nums) { + set.add(num); + } + return set.size() < nums.length; +} +``` + +**最长和谐序列** + +[594. Longest Harmonious Subsequence (Easy)](https://leetcode.com/problems/longest-harmonious-subsequence/description/) + +```html +Input: [1,3,2,2,5,2,3,7] +Output: 5 +Explanation: The longest harmonious subsequence is [3,2,2,2,3]. +``` + +和谐序列中最大数和最小数只差正好为 1,应该注意的是序列的元素不一定是数组的连续元素。 + +```java +public int findLHS(int[] nums) { + Map countForNum = new HashMap<>(); + for (int num : nums) { + countForNum.put(num, countForNum.getOrDefault(num, 0) + 1); + } + int longest = 0; + for (int num : countForNum.keySet()) { + if (countForNum.containsKey(num + 1)) { + longest = Math.max(longest, countForNum.get(num + 1) + countForNum.get(num)); + } + } + return longest; +} +``` + +**最长连续序列** + +[128. Longest Consecutive Sequence (Hard)](https://leetcode.com/problems/longest-consecutive-sequence/description/) + +```html +Given [100, 4, 200, 1, 3, 2], +The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. +``` + +要求以 O(N) 的时间复杂度求解。 + +```java +public int longestConsecutive(int[] nums) { + Map countForNum = new HashMap<>(); + for (int num : nums) { + countForNum.put(num, 1); + } + for (int num : nums) { + forward(countForNum, num); + } + return maxCount(countForNum); +} + +private int forward(Map countForNum, int num) { + if (!countForNum.containsKey(num)) { + return 0; + } + int cnt = countForNum.get(num); + if (cnt > 1) { + return cnt; + } + cnt = forward(countForNum, num + 1) + 1; + countForNum.put(num, cnt); + return cnt; +} + +private int maxCount(Map countForNum) { + int max = 0; + for (int num : countForNum.keySet()) { + max = Math.max(max, countForNum.get(num)); + } + return max; +} +``` + +## 字符串 + +**字符串循环移位包含** + +[编程之美 3.1](#) + +```html +s1 = AABCD, s2 = CDAA +Return : true +``` + +给定两个字符串 s1 和 s2,要求判定 s2 是否能够被 s1 做循环移位得到的字符串包含。 + +s1 进行循环移位的结果是 s1s1 的子字符串,因此只要判断 s2 是否是 s1s1 的子字符串即可。 + +**字符串循环移位** + +[编程之美 2.17](#) + +```html +s = "abcd123" k = 3 +Return "123abcd" +``` + +将字符串向右循环移动 k 位。 + +将 abcd123 中的 abcd 和 123 单独翻转,得到 dcba321,然后对整个字符串进行翻转,得到 123abcd。 + +**字符串中单词的翻转** + +[程序员代码面试指南](#) + +```html +s = "I am a student" +Return "student a am I" +``` + +将每个单词翻转,然后将整个字符串翻转。 + +**两个字符串包含的字符是否完全相同** + +[242. Valid Anagram (Easy)](https://leetcode.com/problems/valid-anagram/description/) + +```html +s = "anagram", t = "nagaram", return true. +s = "rat", t = "car", return false. +``` + +可以用 HashMap 来映射字符与出现次数,然后比较两个字符串出现的字符数量是否相同。 + +由于本题的字符串只包含 26 个小写字符,因此可以使用长度为 26 的整型数组对字符串出现的字符进行统计,不再使用 HashMap。 + +```java +public boolean isAnagram(String s, String t) { + int[] cnts = new int[26]; + for (char c : s.toCharArray()) { + cnts[c - 'a']++; + } + for (char c : t.toCharArray()) { + cnts[c - 'a']--; + } + for (int cnt : cnts) { + if (cnt != 0) { + return false; + } + } + return true; +} +``` + +**计算一组字符集合可以组成的回文字符串的最大长度** + +[409. Longest Palindrome (Easy)](https://leetcode.com/problems/longest-palindrome/description/) + +```html +Input : "abccccdd" +Output : 7 +Explanation : One longest palindrome that can be built is "dccaccd", whose length is 7. +``` + +使用长度为 256 的整型数组来统计每个字符出现的个数,每个字符有偶数个可以用来构成回文字符串。 + +因为回文字符串最中间的那个字符可以单独出现,所以如果有单独的字符就把它放到最中间。 + +```java +public int longestPalindrome(String s) { + int[] cnts = new int[256]; + for (char c : s.toCharArray()) { + cnts[c]++; + } + int palindrome = 0; + for (int cnt : cnts) { + palindrome += (cnt / 2) * 2; + } + if (palindrome < s.length()) { + palindrome++; // 这个条件下 s 中一定有单个未使用的字符存在,可以把这个字符放到回文的最中间 + } + return palindrome; +} +``` + +**字符串同构** + +[205. Isomorphic Strings (Easy)](https://leetcode.com/problems/isomorphic-strings/description/) + +```html +Given "egg", "add", return true. +Given "foo", "bar", return false. +Given "paper", "title", return true. +``` + +记录一个字符上次出现的位置,如果两个字符串中的字符上次出现的位置一样,那么就属于同构。 + +```java +public boolean isIsomorphic(String s, String t) { + int[] preIndexOfS = new int[256]; + int[] preIndexOfT = new int[256]; + for (int i = 0; i < s.length(); i++) { + char sc = s.charAt(i), tc = t.charAt(i); + if (preIndexOfS[sc] != preIndexOfT[tc]) { + return false; + } + preIndexOfS[sc] = i + 1; + preIndexOfT[tc] = i + 1; + } + return true; +} +``` + +**回文子字符串个数** + +[647. Palindromic Substrings (Medium)](https://leetcode.com/problems/palindromic-substrings/description/) + +```html +Input: "aaa" +Output: 6 +Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa". +``` + +从字符串的某一位开始,尝试着去扩展子字符串。 + +```java +private int cnt = 0; + +public int countSubstrings(String s) { + for (int i = 0; i < s.length(); i++) { + extendSubstrings(s, i, i); // 奇数长度 + extendSubstrings(s, i, i + 1); // 偶数长度 + } + return cnt; +} + +private void extendSubstrings(String s, int start, int end) { + while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) { + start--; + end++; + cnt++; + } +} +``` + +**判断一个整数是否是回文数** + +[9. Palindrome Number (Easy)](https://leetcode.com/problems/palindrome-number/description/) + +要求不能使用额外空间,也就不能将整数转换为字符串进行判断。 + +将整数分成左右两部分,右边那部分需要转置,然后判断这两部分是否相等。 + +```java +public boolean isPalindrome(int x) { + if (x == 0) { + return true; + } + if (x < 0 || x % 10 == 0) { + return false; + } + int right = 0; + while (x > right) { + right = right * 10 + x % 10; + x /= 10; + } + return x == right || x == right / 10; +} +``` + +**统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数** + +[696. Count Binary Substrings (Easy)](https://leetcode.com/problems/count-binary-substrings/description/) + +```html +Input: "00110011" +Output: 6 +Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: "0011", "01", "1100", "10", "0011", and "01". +``` + +```java +public int countBinarySubstrings(String s) { + int preLen = 0, curLen = 1, count = 0; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == s.charAt(i - 1)) { + curLen++; + } else { + preLen = curLen; + curLen = 1; + } + + if (preLen >= curLen) { + count++; + } + } + return count; +} +``` + +## 数组与矩阵 + +**把数组中的 0 移到末尾** + +[283. Move Zeroes (Easy)](https://leetcode.com/problems/move-zeroes/description/) + +```html +For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. +``` + +```java +public void moveZeroes(int[] nums) { + int idx = 0; + for (int num : nums) { + if (num != 0) { + nums[idx++] = num; + } + } + while (idx < nums.length) { + nums[idx++] = 0; + } +} +``` + +**改变矩阵维度** + +[566. Reshape the Matrix (Easy)](https://leetcode.com/problems/reshape-the-matrix/description/) + +```html +Input: +nums = +[[1,2], + [3,4]] +r = 1, c = 4 + +Output: +[[1,2,3,4]] + +Explanation: +The row-traversing of nums is [1,2,3,4]. The new reshaped matrix is a 1 * 4 matrix, fill it row by row by using the previous list. +``` + +```java +public int[][] matrixReshape(int[][] nums, int r, int c) { + int m = nums.length, n = nums[0].length; + if (m * n != r * c) { + return nums; + } + int[][] reshapedNums = new int[r][c]; + int index = 0; + for (int i = 0; i < r; i++) { + for (int j = 0; j < c; j++) { + reshapedNums[i][j] = nums[index / n][index % n]; + index++; + } + } + return reshapedNums; +} +``` + +**找出数组中最长的连续 1** + +[485. Max Consecutive Ones (Easy)](https://leetcode.com/problems/max-consecutive-ones/description/) + +```java +public int findMaxConsecutiveOnes(int[] nums) { + int max = 0, cur = 0; + for (int x : nums) { + cur = x == 0 ? 0 : cur + 1; + max = Math.max(max, cur); + } + return max; +} +``` + +**有序矩阵查找** + +[240. Search a 2D Matrix II (Medium)](https://leetcode.com/problems/search-a-2d-matrix-ii/description/) + +```html +[ + [ 1, 5, 9], + [10, 11, 13], + [12, 13, 15] +] +``` + +```java +public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false; + int m = matrix.length, n = matrix[0].length; + int row = 0, col = n - 1; + while (row < m && col >= 0) { + if (target == matrix[row][col]) return true; + else if (target < matrix[row][col]) col--; + else row++; + } + return false; +} +``` + +**有序矩阵的 Kth Element** + +[378. Kth Smallest Element in a Sorted Matrix ((Medium))](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/description/) + +```html +matrix = [ + [ 1, 5, 9], + [10, 11, 13], + [12, 13, 15] +], +k = 8, + +return 13. +``` + +解题参考:[Share my thoughts and Clean Java Code](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/discuss/85173) + +二分查找解法: + +```java +public int kthSmallest(int[][] matrix, int k) { + int m = matrix.length, n = matrix[0].length; + int lo = matrix[0][0], hi = matrix[m - 1][n - 1]; + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + int cnt = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n && matrix[i][j] <= mid; j++) { + cnt++; + } + } + if (cnt < k) lo = mid + 1; + else hi = mid - 1; + } + return lo; +} +``` + +堆解法: + +```java +public int kthSmallest(int[][] matrix, int k) { + int m = matrix.length, n = matrix[0].length; + PriorityQueue pq = new PriorityQueue(); + for(int j = 0; j < n; j++) pq.offer(new Tuple(0, j, matrix[0][j])); + for(int i = 0; i < k - 1; i++) { // 小根堆,去掉 k - 1 个堆顶元素,此时堆顶元素就是第 k 的数 + Tuple t = pq.poll(); + if(t.x == m - 1) continue; + pq.offer(new Tuple(t.x + 1, t.y, matrix[t.x + 1][t.y])); + } + return pq.poll().val; +} + +class Tuple implements Comparable { + int x, y, val; + public Tuple(int x, int y, int val) { + this.x = x; this.y = y; this.val = val; + } + + @Override + public int compareTo(Tuple that) { + return this.val - that.val; + } +} +``` + +**一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数** + +[645. Set Mismatch (Easy)](https://leetcode.com/problems/set-mismatch/description/) + +```html +Input: nums = [1,2,2,4] +Output: [2,3] +``` + +```html +Input: nums = [1,2,2,4] +Output: [2,3] +``` + +最直接的方法是先对数组进行排序,这种方法时间复杂度为 O(NlogN)。本题可以以 O(N) 的时间复杂度、O(1) 空间复杂度来求解。 + +主要思想是通过交换数组元素,使得数组上的元素在正确的位置上。 + +```java +public int[] findErrorNums(int[] nums) { + for (int i = 0; i < nums.length; i++) { + while (nums[i] != i + 1 && nums[nums[i] - 1] != nums[i]) { + swap(nums, i, nums[i] - 1); + } + } + for (int i = 0; i < nums.length; i++) { + if (nums[i] != i + 1) { + return new int[]{nums[i], i + 1}; + } + } + return null; +} + +private void swap(int[] nums, int i, int j) { + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; +} +``` + +类似题目: + +- [448. Find All Numbers Disappeared in an Array (Easy)](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/),寻找所有丢失的元素 +- [442. Find All Duplicates in an Array (Medium)](https://leetcode.com/problems/find-all-duplicates-in-an-array/description/),寻找所有重复的元素。 + +**找出数组中重复的数,数组值在 [1, n] 之间** + +[287. Find the Duplicate Number (Medium)](https://leetcode.com/problems/find-the-duplicate-number/description/) + +要求不能修改数组,也不能使用额外的空间。 + +二分查找解法: + +```java +public int findDuplicate(int[] nums) { + int l = 1, h = nums.length - 1; + while (l <= h) { + int mid = l + (h - l) / 2; + int cnt = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] <= mid) cnt++; + } + if (cnt > mid) h = mid - 1; + else l = mid + 1; + } + return l; +} +``` + +双指针解法,类似于有环链表中找出环的入口: + +```java +public int findDuplicate(int[] nums) { + int slow = nums[0], fast = nums[nums[0]]; + while (slow != fast) { + slow = nums[slow]; + fast = nums[nums[fast]]; + } + fast = 0; + while (slow != fast) { + slow = nums[slow]; + fast = nums[fast]; + } + return slow; +} +``` + +**数组相邻差值的个数** + +[667. Beautiful Arrangement II (Medium)](https://leetcode.com/problems/beautiful-arrangement-ii/description/) + +```html +Input: n = 3, k = 2 +Output: [1, 3, 2] +Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2. +``` + +题目描述:数组元素为 1\~n 的整数,要求构建数组,使得相邻元素的差值不相同的个数为 k。 + +让前 k+1 个元素构建出 k 个不相同的差值,序列为:1 k+1 2 k 3 k-1 ... k/2 k/2+1. + +```java +public int[] constructArray(int n, int k) { + int[] ret = new int[n]; + ret[0] = 1; + for (int i = 1, interval = k; i <= k; i++, interval--) { + ret[i] = i % 2 == 1 ? ret[i - 1] + interval : ret[i - 1] - interval; + } + for (int i = k + 1; i < n; i++) { + ret[i] = i + 1; + } + return ret; +} +``` + +**数组的度** + +[697. Degree of an Array (Easy)](https://leetcode.com/problems/degree-of-an-array/description/) + +```html +Input: [1,2,2,3,1,4,2] +Output: 6 +``` + +题目描述:数组的度定义为元素出现的最高频率,例如上面的数组度为 3。要求找到一个最小的子数组,这个子数组的度和原数组一样。 + +```java +public int findShortestSubArray(int[] nums) { + Map numsCnt = new HashMap<>(); + Map numsLastIndex = new HashMap<>(); + Map numsFirstIndex = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int num = nums[i]; + numsCnt.put(num, numsCnt.getOrDefault(num, 0) + 1); + numsLastIndex.put(num, i); + if (!numsFirstIndex.containsKey(num)) { + numsFirstIndex.put(num, i); + } + } + int maxCnt = 0; + for (int num : nums) { + maxCnt = Math.max(maxCnt, numsCnt.get(num)); + } + int ret = nums.length; + for (int i = 0; i < nums.length; i++) { + int num = nums[i]; + int cnt = numsCnt.get(num); + if (cnt != maxCnt) continue; + ret = Math.min(ret, numsLastIndex.get(num) - numsFirstIndex.get(num) + 1); + } + return ret; +} +``` + +**对角元素相等的矩阵** + +[766. Toeplitz Matrix (Easy)](https://leetcode.com/problems/toeplitz-matrix/description/) + +```html +1234 +5123 +9512 + +In the above grid, the diagonals are "[9]", "[5, 5]", "[1, 1, 1]", "[2, 2, 2]", "[3, 3]", "[4]", and in each diagonal all elements are the same, so the answer is True. +``` + +```java +public boolean isToeplitzMatrix(int[][] matrix) { + for (int i = 0; i < matrix[0].length; i++) { + if (!check(matrix, matrix[0][i], 0, i)) { + return false; + } + } + for (int i = 0; i < matrix.length; i++) { + if (!check(matrix, matrix[i][0], i, 0)) { + return false; + } + } + return true; +} + +private boolean check(int[][] matrix, int expectValue, int row, int col) { + if (row >= matrix.length || col >= matrix[0].length) { + return true; + } + if (matrix[row][col] != expectValue) { + return false; + } + return check(matrix, expectValue, row + 1, col + 1); +} +``` + +**嵌套数组** + +[565. Array Nesting (Medium)](https://leetcode.com/problems/array-nesting/description/) + +```html +Input: A = [5,4,0,3,1,6,2] +Output: 4 +Explanation: +A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2. + +One of the longest S[K]: +S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0} +``` + +题目描述:S[i] 表示一个集合,集合的第一个元素是 A[i],第二个元素是 A[A[i]],如此嵌套下去。求最大的 S[i]。 + +```java +public int arrayNesting(int[] nums) { + int max = 0; + for (int i = 0; i < nums.length; i++) { + int cnt = 0; + for (int j = i; nums[j] != -1; ) { + cnt++; + int t = nums[j]; + nums[j] = -1; // 标记该位置已经被访问 + j = t; + + } + max = Math.max(max, cnt); + } + return max; +} +``` + +**分隔数组** + +[769. Max Chunks To Make Sorted (Medium)](https://leetcode.com/problems/max-chunks-to-make-sorted/description/) + +```html +Input: arr = [1,0,2,3,4] +Output: 4 +Explanation: +We can split into two chunks, such as [1, 0], [2, 3, 4]. +However, splitting into [1, 0], [2], [3], [4] is the highest number of chunks possible. +``` + +题目描述:分隔数组,使得对每部分排序后数组就为有序。 + +```java +public int maxChunksToSorted(int[] arr) { + if (arr == null) return 0; + int ret = 0; + int right = arr[0]; + for (int i = 0; i < arr.length; i++) { + right = Math.max(right, arr[i]); + if (right == i) ret++; + } + return ret; +} +``` + + ## 图 ### 二分图 @@ -7052,3 +7062,4 @@ public int[] countBits(int num) { - 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014. - 《编程之美》小组. 编程之美[M]. 电子工业出版社, 2008. - 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015. + diff --git a/notes/Linux.md b/notes/Linux.md index ebcc347b..14d3b317 100644 --- a/notes/Linux.md +++ b/notes/Linux.md @@ -275,8 +275,6 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。 ## 组成 -

- 最主要的几个组成部分如下: - inode:一个文件占用一个 inode,记录文件的属性,同时记录此文件的内容所在的 block 编号; @@ -287,6 +285,9 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。 - superblock:记录文件系统的整体信息,包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等; - block bitmap:记录 block 是否被使用的位域; +

+ + ## 文件读取 对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block,然后把所有 block 的内容读出来。 @@ -336,7 +337,9 @@ inode 中记录了文件内容所在的 block 编号,但是每个 block 非常 ## 目录 -建立一个目录时,会分配一个 inode 与至少一个 block。block 记录的内容是目录下所有文件的 inode 编号以及文件名。可以看出文件的 inode 本身不记录文件名,文件名记录在目录中,因此新增文件、删除文件、更改文件名这些操作与目录的 w 权限有关。 +建立一个目录时,会分配一个 inode 与至少一个 block。block 记录的内容是目录下所有文件的 inode 编号以及文件名。 + +可以看出文件的 inode 本身不记录文件名,文件名记录在目录中,因此新增文件、删除文件、更改文件名这些操作与目录的 w 权限有关。 ## 日志 diff --git a/notes/MySQL.md b/notes/MySQL.md index 1c575fae..690425db 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -139,7 +139,7 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具 ### 2. 操作 -操作时,首先在根节点进行二分查找,找到一个 key 所在的指针,然后递归地在指针所指向的节点进行查找。直到查找到叶子节点,然后在叶子节点上进行二分查找,找出 key 所对应的 data。 +进行查找操作时,首先在根节点进行二分查找,找到一个 key 所在的指针,然后递归地在指针所指向的节点进行查找。直到查找到叶子节点,然后在叶子节点上进行二分查找,找出 key 所对应的 data。 插入删除操作记录会破坏平衡树的平衡性,因此在插入删除时,需要对树进行一个分裂、合并、旋转等操作。 diff --git a/notes/剑指 offer 题解.md b/notes/剑指 offer 题解.md index 47d5d94e..0c9bd1f9 100644 --- a/notes/剑指 offer 题解.md +++ b/notes/剑指 offer 题解.md @@ -633,11 +633,12 @@ public int RectCover(int n) { ## 解题思路 -当 nums[m] <= nums[h] 的情况下,说明解在 [l, m] 之间,此时令 h = m;否则解在 [m + 1, h] 之间,令 l = m + 1。 +- 当 nums[m] <= nums[h] 的情况下,说明解在 [l, m] 之间,此时令 h = m; +- 否则解在 [m + 1, h] 之间,令 l = m + 1。 -因为 h 的赋值表达式为 h = m,因此循环体的循环条件应该为 l < h,详细解释请见 [Leetcode 题解](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3.md#%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE) 二分查找部分。 +因为 h 的赋值表达式为 h = m,因此循环体的循环条件应该为 l < h,详细解释请见 [Leetcode 题解](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3.md) 二分查找部分。 -但是如果出现 nums[l] == nums[m] == nums[h],那么此时无法确定解在哪个区间,因此需要切换到顺序查找。 +但是如果出现 nums[l] == nums[m] == nums[h],那么此时无法确定解在哪个区间,需要切换到顺序查找。 复杂度:O(logN) + O(1) @@ -1217,8 +1218,7 @@ public ListNode ReverseList(ListNode head) { ### 递归 ```java -public ListNode Merge(ListNode list1, ListNode list2) -{ +public ListNode Merge(ListNode list1, ListNode list2) { if (list1 == null) return list2; if (list2 == null) @@ -1236,8 +1236,7 @@ public ListNode Merge(ListNode list1, ListNode list2) ### 迭代 ```java -public ListNode Merge(ListNode list1, ListNode list2) -{ +public ListNode Merge(ListNode list1, ListNode list2) { ListNode head = new ListNode(-1); ListNode cur = head; while (list1 != null && list2 != null) { @@ -1269,15 +1268,13 @@ public ListNode Merge(ListNode list1, ListNode list2) ## 解题思路 ```java -public boolean HasSubtree(TreeNode root1, TreeNode root2) -{ +public boolean HasSubtree(TreeNode root1, TreeNode root2) { if (root1 == null || root2 == null) return false; return isSubtreeWithRoot(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } -private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) -{ +private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) { if (root2 == null) return true; if (root1 == null) @@ -1298,9 +1295,10 @@ private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) ## 解题思路 +### 递归 + ```java -public void Mirror(TreeNode root) -{ +public void Mirror(TreeNode root) { if (root == null) return; swap(root); @@ -1308,14 +1306,36 @@ public void Mirror(TreeNode root) Mirror(root.right); } -private void swap(TreeNode root) -{ +private void swap(TreeNode root) { TreeNode t = root.left; root.left = root.right; root.right = t; } ``` +### 迭代 + +```java +public void Mirror(TreeNode root) { + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + if (node == null) + continue; + swap(node); + stack.push(node.left); + stack.push(node.right); + } +} + +private void swap(TreeNode node) { + TreeNode t = node.left; + node.left = node.right; + node.right = t; +} +``` + # 28 对称的二叉树 [NowCder](https://www.nowcoder.com/practice/ff05d44dfdb04e1d83bdbdab320efbcb?tpId=13&tqId=11211&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) @@ -1327,15 +1347,13 @@ private void swap(TreeNode root) ## 解题思路 ```java -boolean isSymmetrical(TreeNode pRoot) -{ +boolean isSymmetrical(TreeNode pRoot) { if (pRoot == null) return true; return isSymmetrical(pRoot.left, pRoot.right); } -boolean isSymmetrical(TreeNode t1, TreeNode t2) -{ +boolean isSymmetrical(TreeNode t1, TreeNode t2) { if (t1 == null && t2 == null) return true; if (t1 == null || t2 == null) @@ -1359,8 +1377,7 @@ boolean isSymmetrical(TreeNode t1, TreeNode t2) ## 解题思路 ```java -public ArrayList printMatrix(int[][] matrix) -{ +public ArrayList printMatrix(int[][] matrix) { ArrayList ret = new ArrayList<>(); int r1 = 0, r2 = matrix.length - 1, c1 = 0, c2 = matrix[0].length - 1; while (r1 <= r2 && c1 <= c2) { @@ -1394,25 +1411,21 @@ public ArrayList printMatrix(int[][] matrix) private Stack dataStack = new Stack<>(); private Stack minStack = new Stack<>(); -public void push(int node) -{ +public void push(int node) { dataStack.push(node); minStack.push(minStack.isEmpty() ? node : Math.min(minStack.peek(), node)); } -public void pop() -{ +public void pop() { dataStack.pop(); minStack.pop(); } -public int top() -{ +public int top() { return dataStack.peek(); } -public int min() -{ +public int min() { return minStack.peek(); } ``` @@ -1430,8 +1443,7 @@ public int min() 使用一个栈来模拟压入弹出操作。 ```java -public boolean IsPopOrder(int[] pushSequence, int[] popSequence) -{ +public boolean IsPopOrder(int[] pushSequence, int[] popSequence) { int n = pushSequence.length; Stack stack = new Stack<>(); for (int pushIndex = 0, popIndex = 0; pushIndex < n; pushIndex++) { @@ -1464,8 +1476,7 @@ public boolean IsPopOrder(int[] pushSequence, int[] popSequence) 不需要使用两个队列分别存储当前层的节点和下一层的节点,因为在开始遍历一层的节点时,当前队列中的节点数就是当前层的节点数,只要控制遍历这么多节点数,就能保证这次遍历的都是当前层的节点。 ```java -public ArrayList PrintFromTopToBottom(TreeNode root) -{ +public ArrayList PrintFromTopToBottom(TreeNode root) { Queue queue = new LinkedList<>(); ArrayList ret = new ArrayList<>(); queue.add(root); @@ -1495,8 +1506,7 @@ public ArrayList PrintFromTopToBottom(TreeNode root) ## 解题思路 ```java -ArrayList> Print(TreeNode pRoot) -{ +ArrayList> Print(TreeNode pRoot) { ArrayList> ret = new ArrayList<>(); Queue queue = new LinkedList<>(); queue.add(pRoot); @@ -1529,8 +1539,7 @@ ArrayList> Print(TreeNode pRoot) ## 解题思路 ```java -public ArrayList> Print(TreeNode pRoot) -{ +public ArrayList> Print(TreeNode pRoot) { ArrayList> ret = new ArrayList<>(); Queue queue = new LinkedList<>(); queue.add(pRoot); @@ -1571,15 +1580,13 @@ public ArrayList> Print(TreeNode pRoot) ## 解题思路 ```java -public boolean VerifySquenceOfBST(int[] sequence) -{ +public boolean VerifySquenceOfBST(int[] sequence) { if (sequence == null || sequence.length == 0) return false; return verify(sequence, 0, sequence.length - 1); } -private boolean verify(int[] sequence, int first, int last) -{ +private boolean verify(int[] sequence, int first, int last) { if (last - first <= 1) return true; int rootVal = sequence[last]; @@ -1610,14 +1617,12 @@ private boolean verify(int[] sequence, int first, int last) ```java private ArrayList> ret = new ArrayList<>(); -public ArrayList> FindPath(TreeNode root, int target) -{ +public ArrayList> FindPath(TreeNode root, int target) { backtracking(root, target, new ArrayList<>()); return ret; } -private void backtracking(TreeNode node, int target, ArrayList path) -{ +private void backtracking(TreeNode node, int target, ArrayList path) { if (node == null) return; path.add(node.val); @@ -1641,8 +1646,7 @@ private void backtracking(TreeNode node, int target, ArrayList path) 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的 head。 ```java -public class RandomListNode -{ +public class RandomListNode { int label; RandomListNode next = null; RandomListNode random = null; @@ -1670,8 +1674,7 @@ public class RandomListNode

```java -public RandomListNode Clone(RandomListNode pHead) -{ +public RandomListNode Clone(RandomListNode pHead) { if (pHead == null) return null; // 插入新节点 @@ -1718,14 +1721,12 @@ public RandomListNode Clone(RandomListNode pHead) private TreeNode pre = null; private TreeNode head = null; -public TreeNode Convert(TreeNode root) -{ +public TreeNode Convert(TreeNode root) { inOrder(root); return head; } -private void inOrder(TreeNode node) -{ +private void inOrder(TreeNode node) { if (node == null) return; inOrder(node.left); @@ -1752,21 +1753,18 @@ private void inOrder(TreeNode node) ```java private String deserializeStr; -public String Serialize(TreeNode root) -{ +public String Serialize(TreeNode root) { if (root == null) return "#"; return root.val + " " + Serialize(root.left) + " " + Serialize(root.right); } -public TreeNode Deserialize(String str) -{ +public TreeNode Deserialize(String str) { deserializeStr = str; return Deserialize(); } -private TreeNode Deserialize() -{ +private TreeNode Deserialize() { if (deserializeStr.length() == 0) return null; int index = deserializeStr.indexOf(" "); @@ -1795,8 +1793,7 @@ private TreeNode Deserialize() ```java private ArrayList ret = new ArrayList<>(); -public ArrayList Permutation(String str) -{ +public ArrayList Permutation(String str) { if (str.length() == 0) return ret; char[] chars = str.toCharArray(); @@ -1805,8 +1802,7 @@ public ArrayList Permutation(String str) return ret; } -private void backtracking(char[] chars, boolean[] hasUsed, StringBuilder s) -{ +private void backtracking(char[] chars, boolean[] hasUsed, StringBuilder s) { if (s.length() == chars.length) { ret.add(s.toString()); return; @@ -1836,8 +1832,7 @@ private void backtracking(char[] chars, boolean[] hasUsed, StringBuilder s) 使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不相等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2 ,因为如果多于 i / 2 的话 cnt 就一定不会为 0 。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。 ```java -public int MoreThanHalfNum_Solution(int[] nums) -{ +public int MoreThanHalfNum_Solution(int[] nums) { int majority = nums[0]; for (int i = 1, cnt = 1; i < nums.length; i++) { cnt = nums[i] == majority ? cnt + 1 : cnt - 1; @@ -1868,8 +1863,7 @@ public int MoreThanHalfNum_Solution(int[] nums) 快速排序的 partition() 方法,会返回一个整数 j 使得 a[l..j-1] 小于等于 a[j],且 a[j+1..h] 大于等于 a[j],此时 a[j] 就是数组的第 j 大元素。可以利用这个特性找出数组的第 K 个元素,这种找第 K 个元素的算法称为快速选择算法。 ```java -public ArrayList GetLeastNumbers_Solution(int[] nums, int k) -{ +public ArrayList GetLeastNumbers_Solution(int[] nums, int k) { ArrayList ret = new ArrayList<>(); if (k > nums.length || k <= 0) return ret; @@ -1880,8 +1874,7 @@ public ArrayList GetLeastNumbers_Solution(int[] nums, int k) return ret; } -public void findKthSmallest(int[] nums, int k) -{ +public void findKthSmallest(int[] nums, int k) { int l = 0, h = nums.length - 1; while (l < h) { int j = partition(nums, l, h); @@ -1894,8 +1887,7 @@ public void findKthSmallest(int[] nums, int k) } } -private int partition(int[] nums, int l, int h) -{ +private int partition(int[] nums, int l, int h) { int p = nums[l]; /* 切分元素 */ int i = l, j = h + 1; while (true) { @@ -1909,8 +1901,7 @@ private int partition(int[] nums, int l, int h) return j; } -private void swap(int[] nums, int i, int j) -{ +private void swap(int[] nums, int i, int j) { int t = nums[i]; nums[i] = nums[j]; nums[j] = t; @@ -1927,8 +1918,7 @@ private void swap(int[] nums, int i, int j) 维护一个大小为 K 的最小堆过程如下:在添加一个元素之后,如果大顶堆的大小大于 K,那么需要将大顶堆的堆顶元素去除。 ```java -public ArrayList GetLeastNumbers_Solution(int[] nums, int k) -{ +public ArrayList GetLeastNumbers_Solution(int[] nums, int k) { if (k > nums.length || k <= 0) return new ArrayList<>(); PriorityQueue maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1); @@ -1959,8 +1949,7 @@ private PriorityQueue right = new PriorityQueue<>(); /* 当前数据流读入的元素个数 */ private int N = 0; -public void Insert(Integer val) -{ +public void Insert(Integer val) { /* 插入要保证两个堆存于平衡状态 */ if (N % 2 == 0) { /* N 为偶数的情况下插入到右半边。 @@ -1975,8 +1964,7 @@ public void Insert(Integer val) N++; } -public Double GetMedian() -{ +public Double GetMedian() { if (N % 2 == 0) return (left.peek() + right.peek()) / 2.0; else @@ -1998,16 +1986,14 @@ public Double GetMedian() private int[] cnts = new int[256]; private Queue queue = new LinkedList<>(); -public void Insert(char ch) -{ +public void Insert(char ch) { cnts[ch]++; queue.add(ch); while (!queue.isEmpty() && cnts[queue.peek()] > 1) queue.poll(); } -public char FirstAppearingOnce() -{ +public char FirstAppearingOnce() { return queue.isEmpty() ? '#' : queue.peek(); } ``` @@ -2023,8 +2009,7 @@ public char FirstAppearingOnce() ## 解题思路 ```java -public int FindGreatestSumOfSubArray(int[] nums) -{ +public int FindGreatestSumOfSubArray(int[] nums) { if (nums == null || nums.length == 0) return 0; int greatestSum = Integer.MIN_VALUE; @@ -2044,8 +2029,7 @@ public int FindGreatestSumOfSubArray(int[] nums) ## 解题思路 ```java -public int NumberOf1Between1AndN_Solution(int n) -{ +public int NumberOf1Between1AndN_Solution(int n) { int cnt = 0; for (int m = 1; m <= n; m *= 10) { int a = n / m, b = n % m; @@ -2066,8 +2050,7 @@ public int NumberOf1Between1AndN_Solution(int n) ## 解题思路 ```java -public int getDigitAtIndex(int index) -{ +public int getDigitAtIndex(int index) { if (index < 0) return -1; int place = 1; // 1 表示个位,2 表示 十位... @@ -2085,8 +2068,7 @@ public int getDigitAtIndex(int index) * place 位数的数字组成的字符串长度 * 10, 90, 900, ... */ -private int getAmountOfPlace(int place) -{ +private int getAmountOfPlace(int place) { if (place == 1) return 10; return (int) Math.pow(10, place - 1) * 9; @@ -2096,8 +2078,7 @@ private int getAmountOfPlace(int place) * place 位数的起始数字 * 0, 10, 100, ... */ -private int getBeginNumberOfPlace(int place) -{ +private int getBeginNumberOfPlace(int place) { if (place == 1) return 0; return (int) Math.pow(10, place - 1); @@ -2106,8 +2087,7 @@ private int getBeginNumberOfPlace(int place) /** * 在 place 位数组成的字符串中,第 index 个数 */ -private int getDigitAtIndex(int index, int place) -{ +private int getDigitAtIndex(int index, int place) { int beginNumber = getBeginNumberOfPlace(place); int shiftNumber = index / place; String number = (beginNumber + shiftNumber) + ""; @@ -2129,8 +2109,7 @@ private int getDigitAtIndex(int index, int place) 可以看成是一个排序问题,在比较两个字符串 S1 和 S2 的大小时,应该比较的是 S1+S2 和 S2+S1 的大小,如果 S1+S2 < S2+S1,那么应该把 S1 排在前面,否则应该把 S2 排在前面。 ```java -public String PrintMinNumber(int[] numbers) -{ +public String PrintMinNumber(int[] numbers) { if (numbers == null || numbers.length == 0) return ""; int n = numbers.length; @@ -2156,8 +2135,7 @@ public String PrintMinNumber(int[] numbers) ## 解题思路 ```java -public int numDecodings(String s) -{ +public int numDecodings(String s) { if (s == null || s.length() == 0) return 0; int n = s.length(); @@ -2200,8 +2178,7 @@ public int numDecodings(String s) 应该用动态规划求解,而不是深度优先搜索,深度优先搜索过于复杂,不是最优解。 ```java -public int getMost(int[][] values) -{ +public int getMost(int[][] values) { if (values == null || values.length == 0 || values[0].length == 0) return 0; int n = values[0].length; @@ -2224,8 +2201,7 @@ public int getMost(int[][] values) ## 解题思路 ```java -public int longestSubStringWithoutDuplication(String str) -{ +public int longestSubStringWithoutDuplication(String str) { int curLen = 0; int maxLen = 0; int[] preIndexs = new int[26]; @@ -2257,8 +2233,7 @@ public int longestSubStringWithoutDuplication(String str) ## 解题思路 ```java -public int GetUglyNumber_Solution(int N) -{ +public int GetUglyNumber_Solution(int N) { if (N <= 6) return N; int i2 = 0, i3 = 0, i5 = 0; @@ -2291,8 +2266,7 @@ public int GetUglyNumber_Solution(int N) 最直观的解法是使用 HashMap 对出现次数进行统计,但是考虑到要统计的字符范围有限,因此可以使用整型数组代替 HashMap。 ```java -public int FirstNotRepeatingChar(String str) -{ +public int FirstNotRepeatingChar(String str) { int[] cnts = new int[256]; for (int i = 0; i < str.length(); i++) cnts[str.charAt(i)]++; @@ -2306,8 +2280,7 @@ public int FirstNotRepeatingChar(String str) 以上实现的空间复杂度还不是最优的。考虑到只需要找到只出现一次的字符,那么我们只需要统计的次数信息只有 0,1,更大,使用两个比特位就能存储这些信息。 ```java -public int FirstNotRepeatingChar2(String str) -{ +public int FirstNotRepeatingChar2(String str) { BitSet bs1 = new BitSet(256); BitSet bs2 = new BitSet(256); for (char c : str.toCharArray()) { @@ -2339,15 +2312,13 @@ public int FirstNotRepeatingChar2(String str) private long cnt = 0; private int[] tmp; // 在这里创建辅助数组,而不是在 merge() 递归函数中创建 -public int InversePairs(int[] nums) -{ +public int InversePairs(int[] nums) { tmp = new int[nums.length]; mergeSort(nums, 0, nums.length - 1); return (int) (cnt % 1000000007); } -private void mergeSort(int[] nums, int l, int h) -{ +private void mergeSort(int[] nums, int l, int h) { if (h - l < 1) return; int m = l + (h - l) / 2; @@ -2356,8 +2327,7 @@ private void mergeSort(int[] nums, int l, int h) merge(nums, l, m, h); } -private void merge(int[] nums, int l, int m, int h) -{ +private void merge(int[] nums, int l, int m, int h) { int i = l, j = m + 1, k = l; while (i <= m || j <= h) { if (i > m) @@ -2392,8 +2362,7 @@ private void merge(int[] nums, int l, int m, int h) 当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部重新开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部重新开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。 ```java -public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) -{ +public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { ListNode l1 = pHead1, l2 = pHead2; while (l1 != l2) { l1 = (l1 == null) ? pHead2 : l1.next; @@ -2420,15 +2389,13 @@ Output: ## 解题思路 ```java -public int GetNumberOfK(int[] nums, int K) -{ +public int GetNumberOfK(int[] nums, int K) { int first = binarySearch(nums, K); int last = binarySearch(nums, K + 1); return (first == nums.length || nums[first] != K) ? 0 : last - first; } -private int binarySearch(int[] nums, int K) -{ +private int binarySearch(int[] nums, int K) { int l = 0, h = nums.length; while (l < h) { int m = l + (h - l) / 2; @@ -2453,14 +2420,12 @@ private int binarySearch(int[] nums, int K) private TreeNode ret; private int cnt = 0; -public TreeNode KthNode(TreeNode pRoot, int k) -{ +public TreeNode KthNode(TreeNode pRoot, int k) { inOrder(pRoot, k); return ret; } -private void inOrder(TreeNode root, int k) -{ +private void inOrder(TreeNode root, int k) { if (root == null || cnt >= k) return; inOrder(root.left, k); @@ -2484,8 +2449,7 @@ private void inOrder(TreeNode root, int k) ## 解题思路 ```java -public int TreeDepth(TreeNode root) -{ +public int TreeDepth(TreeNode root) { return root == null ? 0 : 1 + Math.max(TreeDepth(root.left), TreeDepth(root.right)); } ``` @@ -2505,14 +2469,12 @@ public int TreeDepth(TreeNode root) ```java private boolean isBalanced = true; -public boolean IsBalanced_Solution(TreeNode root) -{ +public boolean IsBalanced_Solution(TreeNode root) { height(root); return isBalanced; } -private int height(TreeNode root) -{ +private int height(TreeNode root) { if (root == null || !isBalanced) return 0; int left = height(root.left); @@ -2538,8 +2500,7 @@ private int height(TreeNode root) diff &= -diff 得到出 diff 最右侧不为 0 的位,也就是不存在重复的两个元素在位级表示上最右侧不同的那一位,利用这一位就可以将两个元素区分开来。 ```java -public void FindNumsAppearOnce(int[] nums, int num1[], int num2[]) -{ +public void FindNumsAppearOnce(int[] nums, int num1[], int num2[]) { int diff = 0; for (int num : nums) diff ^= num; @@ -2570,8 +2531,7 @@ public void FindNumsAppearOnce(int[] nums, int num1[], int num2[]) - 如果 sum < target,移动较小的元素,使 sum 变大一些。 ```java -public ArrayList FindNumbersWithSum(int[] array, int sum) -{ +public ArrayList FindNumbersWithSum(int[] array, int sum) { int i = 0, j = array.length - 1; while (i < j) { int cur = array[i] + array[j]; @@ -2604,8 +2564,7 @@ public ArrayList FindNumbersWithSum(int[] array, int sum) ## 解题思路 ```java -public ArrayList> FindContinuousSequence(int sum) -{ +public ArrayList> FindContinuousSequence(int sum) { ArrayList> ret = new ArrayList<>(); int start = 1, end = 2; int curSum = 3; @@ -2648,8 +2607,7 @@ public ArrayList> FindContinuousSequence(int sum) 正确的解法应该是和书上一样,先旋转每个单词,再旋转整个字符串。 ```java -public String ReverseSentence(String str) -{ +public String ReverseSentence(String str) { int n = str.length(); char[] chars = str.toCharArray(); int i = 0, j = 0; @@ -2664,14 +2622,12 @@ public String ReverseSentence(String str) return new String(chars); } -private void reverse(char[] c, int i, int j) -{ +private void reverse(char[] c, int i, int j) { while (i < j) swap(c, i++, j--); } -private void swap(char[] c, int i, int j) -{ +private void swap(char[] c, int i, int j) { char t = c[i]; c[i] = c[j]; c[j] = t; @@ -2691,8 +2647,7 @@ private void swap(char[] c, int i, int j) 先将 "abc" 和 "XYZdef" 分别翻转,得到 "cbafedZYX",然后再把整个字符串翻转得到 "XYZdefabc"。 ```java -public String LeftRotateString(String str, int n) -{ +public String LeftRotateString(String str, int n) { if (n >= str.length()) return str; char[] chars = str.toCharArray(); @@ -2702,14 +2657,12 @@ public String LeftRotateString(String str, int n) return new String(chars); } -private void reverse(char[] chars, int i, int j) -{ +private void reverse(char[] chars, int i, int j) { while (i < j) swap(chars, i++, j--); } -private void swap(char[] chars, int i, int j) -{ +private void swap(char[] chars, int i, int j) { char t = chars[i]; chars[i] = chars[j]; chars[j] = t; @@ -2727,8 +2680,7 @@ private void swap(char[] chars, int i, int j) ## 解题思路 ```java -public ArrayList maxInWindows(int[] num, int size) -{ +public ArrayList maxInWindows(int[] num, int size) { ArrayList ret = new ArrayList<>(); if (size > num.length || size < 1) return ret; @@ -2762,8 +2714,7 @@ public ArrayList maxInWindows(int[] num, int size) 空间复杂度:O(N2) ```java -public List> dicesSum(int n) -{ +public List> dicesSum(int n) { final int face = 6; final int pointNum = face * n; long[][] dp = new long[n + 1][pointNum + 1]; @@ -2790,8 +2741,7 @@ public List> dicesSum(int n) 空间复杂度:O(N) ```java -public List> dicesSum(int n) -{ +public List> dicesSum(int n) { final int face = 6; final int pointNum = face * n; long[][] dp = new long[2][pointNum + 1]; @@ -2829,8 +2779,7 @@ public List> dicesSum(int n) ## 解题思路 ```java -public boolean isContinuous(int[] nums) -{ +public boolean isContinuous(int[] nums) { if (nums.length < 5) return false; Arrays.sort(nums); @@ -2861,8 +2810,7 @@ public boolean isContinuous(int[] nums) 约瑟夫环,圆圈长度为 n 的解可以看成长度为 n-1 的解再加上报数的长度 m。因为是圆圈,所以最后需要对 n 取余。 ```java -public int LastRemaining_Solution(int n, int m) -{ +public int LastRemaining_Solution(int n, int m) { if (n == 0) /* 特殊输入的处理 */ return -1; if (n == 1) /* 返回条件 */ @@ -2884,8 +2832,7 @@ public int LastRemaining_Solution(int n, int m) 使用贪心策略,假设第 i 轮进行卖出操作,买入操作价格应该在 i 之前并且价格最低。 ```java -public int maxProfit(int[] prices) -{ +public int maxProfit(int[] prices) { if (prices == null || prices.length == 0) return 0; int soFarMin = prices[0]; @@ -2915,8 +2862,7 @@ public int maxProfit(int[] prices) 以下实现中,递归的返回条件为 n <= 0,取非后就是 n > 0,递归的主体部分为 sum += Sum_Solution(n - 1),转换为条件语句后就是 (sum += Sum_Solution(n - 1)) > 0。 ```java -public int Sum_Solution(int n) -{ +public int Sum_Solution(int n) { int sum = n; boolean b = (n > 0) && ((sum += Sum_Solution(n - 1)) > 0); return sum; @@ -2938,8 +2884,7 @@ a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进 递归会终止的原因是 (a & b) << 1 最右边会多一个 0,那么继续递归,进位最右边的 0 会慢慢增多,最后进位会变为 0,递归终止。 ```java -public int Add(int a, int b) -{ +public int Add(int a, int b) { return b == 0 ? a : Add(a ^ b, (a & b) << 1); } ``` @@ -2955,8 +2900,7 @@ public int Add(int a, int b) ## 解题思路 ```java -public int[] multiply(int[] A) -{ +public int[] multiply(int[] A) { int n = A.length; int[] B = new int[n]; for (int i = 0, product = 1; i < n; product *= A[i], i++) /* 从左往右累乘 */ @@ -2988,8 +2932,7 @@ Output: ## 解题思路 ```java -public int StrToInt(String str) -{ +public int StrToInt(String str) { if (str == null || str.length() == 0) return 0; boolean isNegative = str.charAt(0) == '-'; diff --git a/notes/消息队列.md b/notes/消息队列.md index e28fcd3f..74155802 100644 --- a/notes/消息队列.md +++ b/notes/消息队列.md @@ -46,17 +46,17 @@ 例如在注册流程中通常需要发送验证邮件来确保注册用户的身份合法,可以使用消息队列使发送验证邮件的操作异步处理,用户在填写完注册信息之后就可以完成注册,而将发送验证邮件这一消息发送到消息队列中。 -只有在业务流程允许异步处理的情况下才能这么做,例如上面的注册流程中,如果要求用户对验证邮件进行点击之后才能完成操作的话,就不能再使用消息队列。 +只有在业务流程允许异步处理的情况下才能这么做,例如上面的注册流程中,如果要求用户对验证邮件进行点击之后才能完成注册的话,就不能再使用消息队列。 ## 流量削锋 -在高并发的场景下,如果短时间有大量的请求会压垮服务器。 +在高并发的场景下,如果短时间有大量的请求到达会压垮服务器。 可以将请求发送到消息队列中,服务器按照其处理能力从消息队列中订阅消息进行处理。 ## 应用解耦 -如果模块之间不直接进行调用,模块之间耦合度很低,那么修改一个模块或者新增一个模块对其它模块的影响会很小,从而实现可扩展性。 +如果模块之间不直接进行调用,模块之间耦合度就会很低,那么修改一个模块或者新增一个模块对其它模块的影响会很小,从而实现可扩展性。 通过使用消息队列,一个模块只需要向消息队列中发送消息,其它模块可以选择性地从消息队列中订阅消息从而完成调用。 diff --git a/notes/算法.md b/notes/算法.md index fb878742..cb5d4dbe 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -1623,10 +1623,10 @@ private List keys(Node x, Key l, Key h) { ## 2-3 查找树 -

- 2-3 查找树引入了 2- 节点和 3- 节点,目的是为了让树平衡。一颗完美平衡的 2-3 查找树的所有空链接到根节点的距离应该是相同的。 +

+ ### 1. 插入操作 插入操作和 BST 的插入操作有很大区别,BST 的插入操作是先进行一次未命中的查找,然后再将节点插入到对应的空链接上。但是 2-3 查找树如果也这么做的话,那么就会破坏了平衡性。它是将新节点插入到叶子节点上。 @@ -2042,24 +2042,26 @@ public class SparseVector { ## 汉诺塔 +

+ 这是一个经典的递归问题,分为三步求解: -1. 将 n-1 个圆盘从 from -> buffer -2. 将 1 个圆盘从 from -> to -3. 将 n-1 个圆盘从 buffer -> to +- 将 n-1 个圆盘从 from -> buffer + +

+ +- 将 1 个圆盘从 from -> to + +

+ +- 将 n-1 个圆盘从 buffer -> to + +

如果只有一个圆盘,那么只需要进行一次移动操作。 从上面的讨论可以知道,an = 2 * an-1 + 1,显然 an = 2n - 1,n 个圆盘需要移动 2n - 1 次。 -

- -

- -

- -

- ```java public class Hanoi { public static void move(int n, String from, String buffer, String to) { @@ -2105,7 +2107,7 @@ from H1 to H3 生成编码时,从根节点出发,向左遍历则添加二进制位 0,向右则添加二进制位 1,直到遍历到根节点,根节点代表的字符的编码就是这个路径编码。 -

+

```java public class Huffman { diff --git a/notes/缓存.md b/notes/缓存.md index e60373dd..449598ff 100644 --- a/notes/缓存.md +++ b/notes/缓存.md @@ -163,7 +163,11 @@ public class LRU implements Iterable { ## 分布式缓存 -使用 Redis、Memcache 等分布式缓存将数据缓存在分布式缓存系统中。相对于本地缓存来说,分布式缓存单独部署,可以根据需求分配硬件资源。不仅如此,服务器集群都可以访问分布式缓存,本地缓存需要在服务器集群之间进行同步,实现和性能开销上都非常大。 +使用 Redis、Memcache 等分布式缓存将数据缓存在分布式缓存系统中。 + +相对于本地缓存来说,分布式缓存单独部署,可以根据需求分配硬件资源。 + +不仅如此,服务器集群都可以访问分布式缓存。而本地缓存需要在服务器集群之间进行同步,实现和性能开销上都非常大。 ## 数据库缓存 @@ -171,7 +175,7 @@ MySQL 等数据库管理系统具有自己的查询缓存机制来提高 SQL 查 # 四、CDN -内容分发网络(Content distribution network,CDN)是一种通过互连的网络系统,利用更靠近用户的服务器更快更可靠地将 HTML、CSS、JavaScript、音乐、图片、视频等静态资源其它数据分发给用户。 +内容分发网络(Content distribution network,CDN)是一种通过互连的网络系统,利用更靠近用户的服务器更快更可靠地将 HTML、CSS、JavaScript、音乐、图片、视频等静态资源分发给用户。 CDN 主要有以下优点: @@ -190,7 +194,7 @@ CDN 主要有以下优点: ## 缓存穿透 -指的是对某个一定不存在的数据进行请求,该请求将会穿透缓存来到数据库。 +指的是对某个一定不存在的数据进行请求,该请求将会穿透缓存到达数据库。 解决方案: @@ -207,6 +211,7 @@ CDN 主要有以下优点: - 为了防止缓存在同一时间大面积过期导致的缓存雪崩,可以通过观察用户行为,合理设置缓存过期时间来实现; - 为了防止缓存服务器宕机出现的缓存雪崩,可以使用分布式缓存,分布式缓存中每一个节点只缓存部分的数据,当某个节点宕机时可以保证其它节点的缓存仍然可用。 +- 也可以在进行缓存预热,避免在系统刚启动不久由于还未将大量数据进行缓存而导致缓存雪崩。 ## 缓存一致性 @@ -258,7 +263,7 @@ Distributed Hash Table(DHT) 是一种哈希分布方式,其目的是为了 上面描述的一致性哈希存在数据分布不均匀的问题,节点存储的数据量有可能会存在很大的不同。 -数据不均匀主要是因为节点在哈希环上分布的不均匀,这种情况在节点数量很少的情况下尤其明显。解决方式是通过增加虚拟节点,然后将虚拟节点映射到真实节点上。虚拟节点的数量比真实节点来得大,那么虚拟节点在哈希环上分布的均匀性就会比原来的真是节点号,从而使得数据分布也更加均匀。 +数据不均匀主要是因为节点在哈希环上分布的不均匀,这种情况在节点数量很少的情况下尤其明显。解决方式是通过增加虚拟节点,然后将虚拟节点映射到真实节点上。虚拟节点的数量比真实节点来得大,那么虚拟节点在哈希环上分布的均匀性就会比原来的真是节点好,从而使得数据分布也更加均匀。 参考资料: diff --git a/notes/设计模式.md b/notes/设计模式.md index ae44213e..d48d7b36 100644 --- a/notes/设计模式.md +++ b/notes/设计模式.md @@ -1851,11 +1851,7 @@ No gumball dispensed ### 与状态模式的比较 -状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。 - -但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。 - -所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。 +状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。 状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。 @@ -1969,7 +1965,7 @@ public abstract class CaffeineBeverage { ``` ```java -public class Coffee extends CaffeineBeverage{ +public class Coffee extends CaffeineBeverage { @Override void brew() { System.out.println("Coffee.brew"); @@ -1983,7 +1979,7 @@ public class Coffee extends CaffeineBeverage{ ``` ```java -public class Tea extends CaffeineBeverage{ +public class Tea extends CaffeineBeverage { @Override void brew() { System.out.println("Tea.brew"); @@ -2238,7 +2234,7 @@ Number of items: 6 ### 意图 -使用什么都不做的空对象来替代 NULL。 +使用什么都不做的空对象来代替 NULL。 一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。 @@ -2393,7 +2389,7 @@ public abstract class TV { ``` ```java -public class Sony extends TV{ +public class Sony extends TV { @Override public void on() { System.out.println("Sony.on()"); @@ -2412,7 +2408,7 @@ public class Sony extends TV{ ``` ```java -public class RCA extends TV{ +public class RCA extends TV { @Override public void on() { System.out.println("RCA.on()"); @@ -2551,9 +2547,6 @@ public abstract class Component { ``` ```java -import java.util.ArrayList; -import java.util.List; - public class Composite extends Component { private List child; @@ -2659,7 +2652,7 @@ Composite:root ### 类图 -装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。 +装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。

@@ -2770,7 +2763,7 @@ public class Client { ### 实现 -观看电影需要操作很多电器,使用外观模式可以实现一键看电影功能。 +观看电影需要操作很多电器,使用外观模式实现一键看电影功能。 ```java public class SubSystem { @@ -2811,7 +2804,7 @@ public class Client { ### 设计原则 -最少知识原则:只和你的密友谈话。也就是客户对象所需要交互的对象应当尽可能少。 +最少知识原则:只和你的密友谈话。也就是说客户对象所需要交互的对象应当尽可能少。 ## 6. 享元(Flyweight) @@ -2822,8 +2815,8 @@ public class Client { ### 类图 - Flyweight:享元对象 -- IntrinsicState:内部状态,相同的项元对象共享 -- ExtrinsicState:外部状态 +- IntrinsicState:内部状态,享元对象共享内部状态 +- ExtrinsicState:外部状态,每个享元对象的外部状态不同

@@ -2854,8 +2847,6 @@ public class ConcreteFlyweight implements Flyweight { ``` ```java -import java.util.HashMap; - public class FlyweightFactory { private HashMap flyweights = new HashMap<>(); From da479e25c6ef9f4268344e0c722903af34932d44 Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Thu, 9 Aug 2018 23:10:49 +0800 Subject: [PATCH 10/53] auto commit --- notes/MySQL.md | 60 ---------------------------------------- notes/剑指 offer 题解.md | 25 ----------------- notes/数据库系统原理.md | 8 +++--- 3 files changed, 4 insertions(+), 89 deletions(-) diff --git a/notes/MySQL.md b/notes/MySQL.md index 02dbe638..690425db 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -304,64 +304,6 @@ Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explai 最有效的方式是使用索引来覆盖查询。 -### 3. 不要在列上使用函数和进行运算 - -在列上使用函数和计算将导致索引失效而进行全表扫描。 - -### 4. 尽量避免使用 != 或 not in 或 <> 等否定操作符 - -尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描。 - -### 5. 尽量避免使用 or 来连接条件 - -尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描。 - -### 6. 多个单列限制应该改成一个多列索引(复合索引)查询 - -因为 MySQL 只能使用一个单列索引,所以为多个列创建单列索引并不能提高 MySQL 的查询性能。正确的做法是将这多个要限定条件的列单独做成一个多列索引(复合索引)。 - -### 7. 查询时要按照复合索引的最左列开始查找 - -查询条件中没有使用复合索引的第一个字段,索引是不会被使用的。复合索引遵守“最左前缀”原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用。 - -假如我们只有一个复合索引 ```age_height_idx(age, height)``` - -如果我们使用 -```mysql -select * from user where height = 170; -``` -那么复合索引 ```age_height_idx(age, height)```将不会被使用。 - -### 8. 尽量不用范围查询 - -如果查询中的某个列有范围查询,则其右边所有列都无法使用索引优化查找。 - -比如说我们使用 -```mysql -select * from users where age > 16 and age < 30 and height = 180 -``` -则索引中 age 右边所有列都无法使用索引优化查找。换句话说,```age_height_idx(age, height)``` 索引等价于 ```age_height_idx(age)```。 - -### 9. 索引不要包含有NULL值的列 - -只要列中包含有 NULL 值,它就不会被包含在索引中,复合索引中只要有一列含有 NULL 值,那么这一列对于此复合索引就是无效的。 - -因此,在数据库设计时,除非有一个很特别的原因使用 NULL 值,不然尽量不要让字段的默认值为 NULL。 - -### 10. 隐式转换可能带来不好的影响 - -当 where 查询条件左右两侧类型不匹配的时候会发生隐式转换,隐式转换可能带来的不好影响就是导致索引失效而进行全表扫描。 - -下面的案例中,brith_date 是字符串,然而匹配的是整数类型,从而发生隐式转换。 - -```mysql -select from users where brith_date = 19950610; -``` - -### 11. like 语句的索引失效问题 - -当我们使用 like “value%” 的方式时是会使用索引的,但是对于 like “%value%” 这样的方式,必定会执行全表查询,这在数据量小的表,不存在性能问题,但是对于海量数据,全表扫描是非常可怕的事情。所以,根据业务需求,考虑使用 ElasticSearch 或 Solr 是个不错的方案。 - ## 重构查询方式 ### 1. 切分大查询 @@ -483,5 +425,3 @@ MySQL 读写分离能提高性能的原因在于: - [How to create unique row ID in sharded databases?](https://stackoverflow.com/questions/788829/how-to-create-unique-row-id-in-sharded-databases) - [SQL Azure Federation – Introduction](http://geekswithblogs.net/shaunxu/archive/2012/01/07/sql-azure-federation-ndash-introduction.aspx "Title of this entry.") - [MySQL 索引背后的数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html) -- [服务端指南 数据存储篇 | MySQL(04) 索引使用的注意事项](http://blog.720ui.com/2017/mysql_core_04_index_item/) -- [mysql 聚簇索引 和聚簇索引 (二级索引)的 那些事](https://blog.csdn.net/bigtree_3721/article/details/51335479) diff --git a/notes/剑指 offer 题解.md b/notes/剑指 offer 题解.md index 00510fc8..0c9bd1f9 100644 --- a/notes/剑指 offer 题解.md +++ b/notes/剑指 offer 题解.md @@ -1296,10 +1296,7 @@ private boolean isSubtreeWithRoot(TreeNode root1, TreeNode root2) { ## 解题思路 ### 递归 -<<<<<<< HEAD -======= ->>>>>>> 0d7909db6d01bdfa0a0fd9abaee469b9ddd2e3a4 ```java public void Mirror(TreeNode root) { if (root == null) @@ -1317,7 +1314,6 @@ private void swap(TreeNode root) { ``` ### 迭代 -<<<<<<< HEAD ```java public void Mirror(TreeNode root) { @@ -1338,27 +1334,6 @@ private void swap(TreeNode node) { node.left = node.right; node.right = t; } -======= -```java -public void Mirror(TreeNode root) { - if (root == null) - return; - Stack stack = new Stack<>(); - stack.push(root); - while (!stack.isEmpty()) { - TreeNode p = stack.pop(); - if (p.left == null && p.right == null) - continue; - TreeNode left = p.left; - p.left = p.right; - p.right = left; - if (p.left != null) - stack.push(p.left); - if (p.right != null) - stack.push(p.right); - } -} ->>>>>>> 0d7909db6d01bdfa0a0fd9abaee469b9ddd2e3a4 ``` # 28 对称的二叉树 diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index 6b8fcd86..151ffc0f 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -389,11 +389,11 @@ MVCC 不能解决幻读的问题,Next-Key Locks 就是为了解决这个问题 ## Gap Locks -间隙锁锁住的是多行,是一个数据范围。间隙锁主要是为了防止出现幻读,但是它会把锁定范围扩大,有时候也会给我们带来麻烦。在数据库参数中,控制间隙锁的参数是 ```innodb_locks_unsafe_for_binlog```, 这个参数默认值是 OFF,也就是启用间隙锁,它是一个bool值,当值为 true 时表示 disable 间隙锁。那为了防止间隙锁是不是直接将 ```innodb_locaks_unsafe_for_binlog``` 设置为 ```true``` 就可以了呢?不一定!而且这个参数会影响到主从复制及灾难恢复,这个方法还尚待商量。 +锁定一个范围内的索引,例如当一个事务执行以下语句,其它事务就不能在 t.c 中插入 15。 -间隙锁的出现主要集中在同一个事务中先 delete 后 insert 的情况下,当我们通过一个参数去删除一条记录的时候,如果参数在数据库中存在,那么这个时候产生的是普通行锁,锁住这个记录,然后删除,最后释放锁。如果这条记录不存在,问题就来了,数据库会扫描索引,发现这个记录不存在,这个时候的 delete 语句获取到的就是一个间隙锁,然后数据库会向左扫描扫到第一个比给定参数小的值,向右扫描扫描到第一个比给定参数大的值,然后以此为上下界限构建一个区间,进而锁住整个区间内的数据,一个特别容易出现死锁的间隙锁诞生了。 - -通过修改 ```innodb_locaks_unsafe_for_binlog``` 参数来取消间隙锁从而达到避免这种情况的死锁的方式尚待商量,那就只有修改代码逻辑,存在才删除,尽量避免去删除不存在的记录。 +```sql +SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE; +``` ## Next-Key Locks From 02f03861376e9328e229f5a7264f8fde421d0395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= <1029579233@qq.com> Date: Thu, 9 Aug 2018 23:48:19 +0800 Subject: [PATCH 11/53] Update Group.md --- other/Group.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/Group.md b/other/Group.md index 60ff3946..e4d54b22 100644 --- a/other/Group.md +++ b/other/Group.md @@ -1,6 +1,6 @@ 创建交流群的主要目的是为了给大家提供一个交流平台,方便大家在学习的过程中互相讨论。 -这个交流群不是一个笔者的问题回答群,我更希望大家能够愿意积极回答,我相信提问和回答的过程都可以帮助大家对知识的掌握程度。 +这个交流群不是一个笔者的问题回答群,我更希望大家能够愿意积极回答,我相信提问和回答的过程都可以提高大家对知识的掌握程度。 因为笔者白天要上班,因此不能及时进行回复,大部分时间会处于潜水状态。 From e08c1f0e95d862edfbeef8cbd0c7a161430040ba Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Thu, 9 Aug 2018 23:49:33 +0800 Subject: [PATCH 12/53] auto commit --- notes/数据库系统原理.md | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index 151ffc0f..e7ef804b 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -383,13 +383,13 @@ MVCC 不能解决幻读的问题,Next-Key Locks 就是为了解决这个问题 ## Record Locks -锁定的对象是记录的索引,而不是记录本身。 +锁定一个记录上的索引,而不是记录本身。 如果表没有设置索引,InnoDB 会自动在主键上创建隐藏的聚集索引,因此 Record Locks 依然可以使用。 ## Gap Locks -锁定一个范围内的索引,例如当一个事务执行以下语句,其它事务就不能在 t.c 中插入 15。 +锁定索引之间的间隙,但是不包含索引本身。例如当一个事务执行以下语句,其它事务就不能在 t.c 中插入 15。 ```sql SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE; @@ -397,28 +397,14 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE; ## Next-Key Locks -它是 Record Locks 和 Gap Locks 的结合,不仅锁定一个记录,也锁定范围内的索引。在 user 中有以下记录: +它是 Record Locks 和 Gap Locks 的结合,不仅锁定一个记录上的索引,也锁定范围内的索引。例如一个索引包含以下值:10, 11, 13, and 20,那么就需要锁定以下区间: ```sql -| id | last_name | first_name | age | -|------|-------------|--------------|-------| -| 4 | stark | tony | 21 | -| 1 | tom | hiddleston | 30 | -| 3 | morgan | freeman | 40 | -| 5 | jeff | dean | 50 | -| 2 | donald | trump | 80 | -+------|-------------|--------------|-------+ -``` - -那么就需要锁定以下范围: - -```sql -(-∞, 21] -(21, 30] -(30, 40] -(40, 50] -(50, 80] -(80, ∞) +(negative infinity, 10] +(10, 11] +(11, 13] +(13, 20] +(20, positive infinity) ``` # 七、关系数据库设计理论 From 2015cf3e8594d22723d67e5d18801b71a8cb37ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= <1029579233@qq.com> Date: Fri, 10 Aug 2018 16:41:20 +0800 Subject: [PATCH 13/53] Update README.md --- README.md | 66 +++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 8dbf0507..f4c2b510 100644 --- a/README.md +++ b/README.md @@ -13,151 +13,151 @@ ## 算法 :pencil2: -> [剑指 Offer 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/剑指%20offer%20题解.md) +- [剑指 Offer 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/剑指%20offer%20题解.md) 目录根据原书第二版进行编排,代码和原书有所不同,尽量比原书更简洁。 -> [Leetcode 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode%20题解.md) +- [Leetcode 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode%20题解.md) 对题目做了一个大致分类,并对每种题型的解题思路做了总结。 -> [算法](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/算法.md) +- [算法](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/算法.md) 排序、并查集、栈和队列、红黑树、散列表。 ## 操作系统 :computer: -> [计算机操作系统](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机操作系统.md) +- [计算机操作系统](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机操作系统.md) 进程管理、内存管理、设备管理、链接。 -> [Linux](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Linux.md) +- [Linux](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Linux.md) 基本实现原理以及基本操作。 ## 网络 :cloud: -> [计算机网络](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机网络.md) +- [计算机网络](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机网络.md) 物理层、链路层、网络层、运输层、应用层。 -> [HTTP](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/HTTP.md) +- [HTTP](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/HTTP.md) 方法、状态码、Cookie、缓存、连接管理、HTTPs、HTTP 2.0。 -> [Socket](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Socket.md) +- [Socket](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Socket.md) I/O 模型、I/O 多路复用。 ## 面向对象 :couple: -> [设计模式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/设计模式.md) +- [设计模式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/设计模式.md) 实现了 Gof 的 23 种设计模式。 -> [面向对象思想](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/面向对象思想.md) +- [面向对象思想](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/面向对象思想.md) 三大原则(继承、封装、多态)、类图、设计原则。 ## 数据库 :floppy_disk: -> [数据库系统原理](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/数据库系统原理.md) +- [数据库系统原理](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/数据库系统原理.md) 事务、锁、隔离级别、MVCC、间隙锁、范式。 -> [SQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/SQL.md) +- [SQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/SQL.md) SQL 基本语法。 -> [Leetcode-Database 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode-Database%20题解.md) +- [Leetcode-Database 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode-Database%20题解.md) Leetcode 上数据库题目的解题记录。 -> [MySQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/MySQL.md) +- [MySQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/MySQL.md) 存储引擎、索引、查询优化、切分、复制。 -> [Redis](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Redis.md) +- [Redis](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Redis.md) 五种数据类型、字典和跳跃表数据结构、使用场景、和 Memcache 的比较、淘汰策略、持久化、文件事件的 Reactor 模式、复制。 ## Java :coffee: -> [Java 基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20基础.md) +- [Java 基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20基础.md) 不会涉及很多基本语法介绍,主要是一些实现原理以及关键特性。 -> [Java 容器](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20容器.md) +- [Java 容器](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20容器.md) 源码分析:ArrayList、Vector、CopyOnWriteArrayList、LinkedList、HashMap、ConcurrentHashMap、LinkedHashMap、WeekHashMap。 -> [Java 并发](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20并发.md) +- [Java 并发](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20并发.md) 线程使用方式、两种互斥同步方法、线程协作、JUC、线程安全、内存模型、锁优化。 -> [Java 虚拟机](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20虚拟机.md) +- [Java 虚拟机](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20虚拟机.md) 运行时数据区域、垃圾收集、类加载。 -> [Java I/O](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20IO.md) +- [Java I/O](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20IO.md) NIO 的原理以及实例。 ## 系统设计 :bulb: -> [系统设计基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/系统设计基础.md) +- [系统设计基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/系统设计基础.md) 性能、伸缩性、扩展性、可用性、安全性 -> [分布式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式.md) +- [分布式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式.md) 分布式锁、分布式事务、CAP、BASE、Paxos、Raft -> [集群](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/集群.md) +- [集群](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/集群.md) 负载均衡、Session 管理 -> [攻击技术](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/攻击技术.md) +- [攻击技术](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/攻击技术.md) XSS、CSRF、SQL 注入、DDoS -> [缓存](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/缓存.md) +- [缓存](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/缓存.md) 缓存特征、缓存位置、缓存问题、数据分布、一致性哈希、LRU、CDN -> [消息队列](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/消息队列.md) +- [消息队列](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/消息队列.md) 消息处理模型、使用场景、可靠性 ## 工具 :hammer: -> [Git](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Git.md) +- [Git](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Git.md) 一些 Git 的使用和概念。 -> [Docker](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Docker.md) +- [Docker](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Docker.md) Docker 基本原理。 -> [正则表达式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/正则表达式.md) +- [正则表达式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/正则表达式.md) 正则表达式基本语法。 -> [构建工具](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/构建工具.md) +- [构建工具](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/构建工具.md) 构建工具的基本概念、主流构建工具介绍。 ## 编码实践 :speak_no_evil: -> [重构](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/重构.md) +- [重构](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/重构.md) 参考 重构 改善既有代码的设计。 -> [代码可读性](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码可读性.md) +- [代码可读性](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码可读性.md) 参考 编写可读代码的艺术。 -> [代码风格规范](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码风格规范.md) +- [代码风格规范](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码风格规范.md) Google 开源项目的代码风格规范。 From 8afe65df0c84979c576949f5e836a507ff7091d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= <1029579233@qq.com> Date: Fri, 10 Aug 2018 16:42:23 +0800 Subject: [PATCH 14/53] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f4c2b510..728fb40c 100644 --- a/README.md +++ b/README.md @@ -15,25 +15,25 @@ - [剑指 Offer 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/剑指%20offer%20题解.md) -目录根据原书第二版进行编排,代码和原书有所不同,尽量比原书更简洁。 + 目录根据原书第二版进行编排,代码和原书有所不同,尽量比原书更简洁。 - [Leetcode 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode%20题解.md) -对题目做了一个大致分类,并对每种题型的解题思路做了总结。 + 对题目做了一个大致分类,并对每种题型的解题思路做了总结。 - [算法](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/算法.md) -排序、并查集、栈和队列、红黑树、散列表。 + 排序、并查集、栈和队列、红黑树、散列表。 ## 操作系统 :computer: - [计算机操作系统](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机操作系统.md) -进程管理、内存管理、设备管理、链接。 + 进程管理、内存管理、设备管理、链接。 - [Linux](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Linux.md) -基本实现原理以及基本操作。 + 基本实现原理以及基本操作。 ## 网络 :cloud: From d2bafee9a193e05782c33d9ae88a253971ccb6bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= <1029579233@qq.com> Date: Fri, 10 Aug 2018 16:43:23 +0800 Subject: [PATCH 15/53] Update README.md --- README.md | 56 +++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 728fb40c..4de16ff4 100644 --- a/README.md +++ b/README.md @@ -39,127 +39,127 @@ - [计算机网络](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机网络.md) -物理层、链路层、网络层、运输层、应用层。 + 物理层、链路层、网络层、运输层、应用层。 - [HTTP](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/HTTP.md) -方法、状态码、Cookie、缓存、连接管理、HTTPs、HTTP 2.0。 + 方法、状态码、Cookie、缓存、连接管理、HTTPs、HTTP 2.0。 - [Socket](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Socket.md) -I/O 模型、I/O 多路复用。 + I/O 模型、I/O 多路复用。 ## 面向对象 :couple: - [设计模式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/设计模式.md) -实现了 Gof 的 23 种设计模式。 + 实现了 Gof 的 23 种设计模式。 - [面向对象思想](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/面向对象思想.md) -三大原则(继承、封装、多态)、类图、设计原则。 + 三大原则(继承、封装、多态)、类图、设计原则。 ## 数据库 :floppy_disk: - [数据库系统原理](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/数据库系统原理.md) -事务、锁、隔离级别、MVCC、间隙锁、范式。 + 事务、锁、隔离级别、MVCC、间隙锁、范式。 - [SQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/SQL.md) -SQL 基本语法。 + SQL 基本语法。 - [Leetcode-Database 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode-Database%20题解.md) -Leetcode 上数据库题目的解题记录。 + Leetcode 上数据库题目的解题记录。 - [MySQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/MySQL.md) -存储引擎、索引、查询优化、切分、复制。 + 存储引擎、索引、查询优化、切分、复制。 - [Redis](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Redis.md) -五种数据类型、字典和跳跃表数据结构、使用场景、和 Memcache 的比较、淘汰策略、持久化、文件事件的 Reactor 模式、复制。 + 五种数据类型、字典和跳跃表数据结构、使用场景、和 Memcache 的比较、淘汰策略、持久化、文件事件的 Reactor 模式、复制。 ## Java :coffee: - [Java 基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20基础.md) -不会涉及很多基本语法介绍,主要是一些实现原理以及关键特性。 + 不会涉及很多基本语法介绍,主要是一些实现原理以及关键特性。 - [Java 容器](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20容器.md) -源码分析:ArrayList、Vector、CopyOnWriteArrayList、LinkedList、HashMap、ConcurrentHashMap、LinkedHashMap、WeekHashMap。 + 源码分析:ArrayList、Vector、CopyOnWriteArrayList、LinkedList、HashMap、ConcurrentHashMap、LinkedHashMap、WeekHashMap。 - [Java 并发](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20并发.md) -线程使用方式、两种互斥同步方法、线程协作、JUC、线程安全、内存模型、锁优化。 + 线程使用方式、两种互斥同步方法、线程协作、JUC、线程安全、内存模型、锁优化。 - [Java 虚拟机](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20虚拟机.md) -运行时数据区域、垃圾收集、类加载。 + 运行时数据区域、垃圾收集、类加载。 - [Java I/O](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20IO.md) -NIO 的原理以及实例。 + NIO 的原理以及实例。 ## 系统设计 :bulb: - [系统设计基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/系统设计基础.md) -性能、伸缩性、扩展性、可用性、安全性 + 性能、伸缩性、扩展性、可用性、安全性 - [分布式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式.md) -分布式锁、分布式事务、CAP、BASE、Paxos、Raft + 分布式锁、分布式事务、CAP、BASE、Paxos、Raft - [集群](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/集群.md) -负载均衡、Session 管理 + 负载均衡、Session 管理 - [攻击技术](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/攻击技术.md) -XSS、CSRF、SQL 注入、DDoS + XSS、CSRF、SQL 注入、DDoS - [缓存](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/缓存.md) -缓存特征、缓存位置、缓存问题、数据分布、一致性哈希、LRU、CDN + 缓存特征、缓存位置、缓存问题、数据分布、一致性哈希、LRU、CDN - [消息队列](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/消息队列.md) -消息处理模型、使用场景、可靠性 + 消息处理模型、使用场景、可靠性 ## 工具 :hammer: - [Git](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Git.md) -一些 Git 的使用和概念。 + 一些 Git 的使用和概念。 - [Docker](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Docker.md) -Docker 基本原理。 + Docker 基本原理。 - [正则表达式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/正则表达式.md) -正则表达式基本语法。 + 正则表达式基本语法。 - [构建工具](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/构建工具.md) -构建工具的基本概念、主流构建工具介绍。 + 构建工具的基本概念、主流构建工具介绍。 ## 编码实践 :speak_no_evil: - [重构](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/重构.md) -参考 重构 改善既有代码的设计。 + 参考 重构 改善既有代码的设计。 - [代码可读性](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码可读性.md) -参考 编写可读代码的艺术。 + 参考 编写可读代码的艺术。 - [代码风格规范](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码风格规范.md) -Google 开源项目的代码风格规范。 + Google 开源项目的代码风格规范。 ## 后记 :memo: From 305623c80f114d3bc4d04689902b9428d4c8a705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= <1029579233@qq.com> Date: Fri, 10 Aug 2018 16:49:08 +0800 Subject: [PATCH 16/53] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4de16ff4..42788e54 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@
@@ -163,7 +163,7 @@ ## 后记 :memo: -**About** +### About 这个仓库是笔者的一个学习笔记,主要总结一些比较重要的知识点,希望对大家有所帮助。 @@ -171,7 +171,7 @@ [BOOKLIST](https://github.com/CyC2018/Interview-Notebook/blob/master/BOOKLIST.md),这个书单是笔者至今看的一些比较好的技术书籍,虽然没有全都看完,但每本书多多少少都看了一部分。 -**How To Contribute** +### How To Contribute 笔记内容是笔者一个字一个字打上去的,难免会有一些笔误,如果发现笔误可直接在相应文档进行编辑修改。 @@ -179,13 +179,13 @@ 欢迎在 Issue 中提交对本仓库的改进建议~ -**Authorization** +### Authorization 虽然没有加开源协议,但是允许非商业性使用。 转载使用请注明出处,谢谢! -**Typesetting** +### Typesetting 笔记内容按照 [中文文案排版指北](http://mazhuang.org/wiki/chinese-copywriting-guidelines/) 进行排版,以保证内容的可读性。 @@ -193,7 +193,7 @@ 笔者将自己实现的文档排版功能提取出来,放在 Github Page 中,无需下载安装即可免费使用:[Text-Typesetting](https://github.com/CyC2018/Markdown-Typesetting)。 -**Uploading** +### Uploading 笔者在本地使用为知笔记软件进行书写,为了方便将本地笔记内容上传到 Github 上,实现了一整套自动化上传方案,包括文本文件的导出、提取图片、Markdown 文档转换、Git 同步。 @@ -201,15 +201,15 @@ 笔者将自己实现文档转换功能提取出来,方便大家在需要将本地 Markdown 上传到 Github,或者制作项目 README 文档时生成目录时使用:[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。 -**Statement** +### Statement 本仓库不参与商业行为,不向读者收取任何费用。(This repository is not engaging in business activities, and does not charge readers any fee.) -**Logo** +### Logo Power by [logomakr](https://logomakr.com/). -**Acknowledgements** +### Acknowledgements 感谢以下人员对本仓库做出的贡献,当然不仅仅只有这些贡献者,这里就不一一列举了。如果你希望被添加到这个名单中,并且提交过 Issue 或者 PR,请与笔者联系。 From b6156c4247f05d29a65564f0e337545fde70fea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=B0=B8=E5=B7=9D?= <1029579233@qq.com> Date: Fri, 10 Aug 2018 18:33:36 +0800 Subject: [PATCH 17/53] =?UTF-8?q?Update=20Leetcode=20=E9=A2=98=E8=A7=A3.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notes/Leetcode 题解.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index 102fe9b6..d8e53838 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -57,9 +57,9 @@ ## 贪心思想 -贪心思想保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。 +保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。 -**分配饼干** +**分配饼干** [455. Assign Cookies (Easy)](https://leetcode.com/problems/assign-cookies/description/) @@ -74,7 +74,7 @@ You need to output 2. 题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。 -因为最小的孩子最容易得到满足,因此先满足最小孩子。给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因此贪心策略 +给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因为最小的孩子最容易得到满足,所以先满足最小的孩子。 证明:假设在某次选择中,贪心策略选择给当前满足度最小的孩子分配第 m 个饼干,第 m 个饼干为可以满足该孩子的最小饼干。假设存在一种最优策略,给该孩子分配第 n 个饼干,并且 m < n。我们可以发现,经过这一轮分配,贪心策略分配后剩下的饼干一定有一个比最优策略来得大。因此在后续的分配中,贪心策略一定能满足更多的孩子。也就是说不存在比贪心策略更优的策略,即贪心策略就是最优策略。 From 06b9804ec7f79f2340d9e97b4e4fc9b8a9adb726 Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Fri, 10 Aug 2018 21:58:11 +0800 Subject: [PATCH 18/53] auto commit --- notes/Leetcode 题解.md | 970 ++++++++++++++++---------------- notes/Leetcode-Database 题解.md | 20 +- notes/设计模式.md | 12 +- 3 files changed, 508 insertions(+), 494 deletions(-) diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index 102fe9b6..44f3d9dc 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -1,18 +1,18 @@ * [算法思想](#算法思想) - * [贪心思想](#贪心思想) * [双指针](#双指针) * [排序](#排序) * [快速选择](#快速选择) * [堆排序](#堆排序) * [桶排序](#桶排序) * [荷兰国旗问题](#荷兰国旗问题) + * [贪心思想](#贪心思想) * [二分查找](#二分查找) + * [分治](#分治) * [搜索](#搜索) * [BFS](#bfs) * [DFS](#dfs) * [Backtracking](#backtracking) - * [分治](#分治) * [动态规划](#动态规划) * [斐波那契数列](#斐波那契数列) * [矩阵路径](#矩阵路径) @@ -55,9 +55,449 @@ # 算法思想 +## 双指针 + +双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。 + +**有序数组的 Two Sum** + +[Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/) + +```html +Input: numbers={2, 7, 11, 15}, target=9 +Output: index1=1, index2=2 +``` + +题目描述:在有序数组中找出两个数,使它们的和为 target。 + +使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。 + +- 如果两个指针指向元素的和 sum == target,那么得到要求的结果; +- 如果 sum > target,移动较大的元素,使 sum 变小一些; +- 如果 sum < target,移动较小的元素,使 sum 变大一些。 + +```java +public int[] twoSum(int[] numbers, int target) { + int i = 0, j = numbers.length - 1; + while (i < j) { + int sum = numbers[i] + numbers[j]; + if (sum == target) { + return new int[]{i + 1, j + 1}; + } else if (sum < target) { + i++; + } else { + j--; + } + } + return null; +} +``` + +**两数平方和** + +[633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/) + +```html +Input: 5 +Output: True +Explanation: 1 * 1 + 2 * 2 = 5 +``` + +题目描述:判断一个数是否为两个数的平方和,例如 5 = 12 + 22。 + +```java +public boolean judgeSquareSum(int c) { + int i = 0, j = (int) Math.sqrt(c); + while (i <= j) { + int powSum = i * i + j * j; + if (powSum == c) { + return true; + } else if (powSum > c) { + j--; + } else { + i++; + } + } + return false; +} +``` + +**反转字符串中的元音字符** + +[345. Reverse Vowels of a String (Easy)](https://leetcode.com/problems/reverse-vowels-of-a-string/description/) + +```html +Given s = "leetcode", return "leotcede". +``` + +使用双指针,指向待反转的两个元音字符,一个指针从头向尾遍历,一个指针从尾到头遍历。 + +```java +private final static HashSet vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U')); + +public String reverseVowels(String s) { + int i = 0, j = s.length() - 1; + char[] result = new char[s.length()]; + while (i <= j) { + char ci = s.charAt(i); + char cj = s.charAt(j); + if (!vowels.contains(ci)) { + result[i++] = ci; + } else if (!vowels.contains(cj)) { + result[j--] = cj; + } else { + result[i++] = cj; + result[j--] = ci; + } + } + return new String(result); +} +``` + +**回文字符串** + +[680. Valid Palindrome II (Easy)](https://leetcode.com/problems/valid-palindrome-ii/description/) + +```html +Input: "abca" +Output: True +Explanation: You could delete the character 'c'. +``` + +题目描述:可以删除一个字符,判断是否能构成回文字符串。 + +```java +public boolean validPalindrome(String s) { + int i = -1, j = s.length(); + while (++i < --j) { + if (s.charAt(i) != s.charAt(j)) { + return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j); + } + } + return true; +} + +private boolean isPalindrome(String s, int i, int j) { + while (i < j) { + if (s.charAt(i++) != s.charAt(j--)) { + return false; + } + } + return true; +} +``` + +**归并两个有序数组** + +[88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/) + +```html +Input: +nums1 = [1,2,3,0,0,0], m = 3 +nums2 = [2,5,6], n = 3 + +Output: [1,2,2,3,5,6] +``` + +题目描述:把归并结果存到第一个数组上。 + +需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值。 + +```java +public void merge(int[] nums1, int m, int[] nums2, int n) { + int index1 = m - 1, index2 = n - 1; + int indexMerge = m + n - 1; + while (index1 >= 0 || index2 >= 0) { + if (index1 < 0) { + nums1[indexMerge--] = nums2[index2--]; + } else if (index2 < 0) { + nums1[indexMerge--] = nums1[index1--]; + } else if (nums1[index1] > nums2[index2]) { + nums1[indexMerge--] = nums1[index1--]; + } else { + nums1[indexMerge--] = nums2[index2--]; + } + } +} +``` + +**判断链表是否存在环** + +[141. Linked List Cycle (Easy)](https://leetcode.com/problems/linked-list-cycle/description/) + +使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。 + +```java +public boolean hasCycle(ListNode head) { + if (head == null) { + return false; + } + ListNode l1 = head, l2 = head.next; + while (l1 != null && l2 != null && l2.next != null) { + if (l1 == l2) { + return true; + } + l1 = l1.next; + l2 = l2.next.next; + } + return false; +} +``` + +**最长子序列** + +[524. Longest Word in Dictionary through Deleting (Medium)](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/description/) + +``` +Input: +s = "abpcplea", d = ["ale","apple","monkey","plea"] + +Output: +"apple" +``` + +题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最大字符串。 + +```java +public String findLongestWord(String s, List d) { + String longestWord = ""; + for (String target : d) { + int l1 = longestWord.length(), l2 = target.length(); + if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) { + continue; + } + if (isValid(s, target)) { + longestWord = target; + } + } + return longestWord; +} + +private boolean isValid(String s, String target) { + int i = 0, j = 0; + while (i < s.length() && j < target.length()) { + if (s.charAt(i) == target.charAt(j)) { + j++; + } + i++; + } + return j == target.length(); +} +``` + +## 排序 + +### 快速选择 + +用于求解 **Kth Element** 问题,使用快速排序的 partition() 进行实现。 + +需要先打乱数组,否则最坏情况下时间复杂度为 O(N2)。 + +### 堆排序 + +用于求解 **TopK Elements** 问题,通过维护一个大小为 K 的堆,堆中的元素就是 TopK Elements。 + +堆排序也可以用于求解 Kth Element 问题,堆顶元素就是 Kth Element。 + +快速选择也可以求解 TopK Elements 问题,因为找到 Kth Element 之后,再遍历一次数组,所有小于等于 Kth Element 的元素都是 TopK Elements。 + +可以看到,快速选择和堆排序都可以求解 Kth Element 和 TopK Elements 问题。 + +**Kth Element** + +[215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/) + +**排序** :时间复杂度 O(NlogN),空间复杂度 O(1) + +```java +public int findKthLargest(int[] nums, int k) { + Arrays.sort(nums); + return nums[nums.length - k]; +} +``` + +**堆排序** :时间复杂度 O(NlogK),空间复杂度 O(K)。 + +```java +public int findKthLargest(int[] nums, int k) { + PriorityQueue pq = new PriorityQueue<>(); // 小顶堆 + for (int val : nums) { + pq.add(val); + if (pq.size() > k) // 维护堆的大小为 K + pq.poll(); + } + return pq.peek(); +} +``` + +**快速选择** :时间复杂度 O(N),空间复杂度 O(1) + +```java +public int findKthLargest(int[] nums, int k) { + k = nums.length - k; + int l = 0, h = nums.length - 1; + while (l < h) { + int j = partition(nums, l, h); + if (j == k) { + break; + } else if (j < k) { + l = j + 1; + } else { + h = j - 1; + } + } + return nums[k]; +} + +private int partition(int[] a, int l, int h) { + int i = l, j = h + 1; + while (true) { + while (a[++i] < a[l] && i < h) ; + while (a[--j] > a[l] && j > l) ; + if (i >= j) { + break; + } + swap(a, i, j); + } + swap(a, l, j); + return j; +} + +private void swap(int[] a, int i, int j) { + int t = a[i]; + a[i] = a[j]; + a[j] = t; +} +``` + +### 桶排序 + +**出现频率最多的 k 个数** + +[347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/) + +```html +Given [1,1,1,2,2,3] and k = 2, return [1,2]. +``` + +设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率,即第 i 个桶中存储的数出现的频率为 i。 + +把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。 + +```java +public List topKFrequent(int[] nums, int k) { + Map frequencyForNum = new HashMap<>(); + for (int num : nums) { + frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1); + } + List[] buckets = new ArrayList[nums.length + 1]; + for (int key : frequencyForNum.keySet()) { + int frequency = frequencyForNum.get(key); + if (buckets[frequency] == null) { + buckets[frequency] = new ArrayList<>(); + } + buckets[frequency].add(key); + } + List topK = new ArrayList<>(); + for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) { + if (buckets[i] != null) { + topK.addAll(buckets[i]); + } + } + return topK; +} +``` + +**按照字符出现次数对字符串排序** + +[451. Sort Characters By Frequency (Medium)](https://leetcode.com/problems/sort-characters-by-frequency/description/) + +```html +Input: +"tree" + +Output: +"eert" + +Explanation: +'e' appears twice while 'r' and 't' both appear once. +So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer. +``` + +```java +public String frequencySort(String s) { + Map frequencyForNum = new HashMap<>(); + for (char c : s.toCharArray()) + frequencyForNum.put(c, frequencyForNum.getOrDefault(c, 0) + 1); + + List[] frequencyBucket = new ArrayList[s.length() + 1]; + for (char c : frequencyForNum.keySet()) { + int f = frequencyForNum.get(c); + if (frequencyBucket[f] == null) { + frequencyBucket[f] = new ArrayList<>(); + } + frequencyBucket[f].add(c); + } + StringBuilder str = new StringBuilder(); + for (int i = frequencyBucket.length - 1; i >= 0; i--) { + if (frequencyBucket[i] == null) { + continue; + } + for (char c : frequencyBucket[i]) { + for (int j = 0; j < i; j++) { + str.append(c); + } + } + } + return str.toString(); +} +``` + +### 荷兰国旗问题 + +荷兰国旗包含三种颜色:红、白、蓝。 + +有三种颜色的球,算法的目标是将这三种球按颜色顺序正确地排列。 + +它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。 + +

+ +**按颜色进行排序** + +[75. Sort Colors (Medium)](https://leetcode.com/problems/sort-colors/description/) + +```html +Input: [2,0,2,1,1,0] +Output: [0,0,1,1,2,2] +``` + +题目描述:只有 0/1/2 三种颜色。 + +```java +public void sortColors(int[] nums) { + int zero = -1, one = 0, two = nums.length; + while (one < two) { + if (nums[one] == 0) { + swap(nums, ++zero, one++); + } else if (nums[one] == 2) { + swap(nums, --two, one); + } else { + ++one; + } + } +} + +private void swap(int[] nums, int i, int j) { + int t = nums[i]; + nums[i] = nums[j]; + nums[j] = t; +} +``` + ## 贪心思想 -贪心思想保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。 +保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。 **分配饼干** @@ -74,7 +514,7 @@ You need to output 2. 题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。 -因为最小的孩子最容易得到满足,因此先满足最小孩子。给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因此贪心策略 +给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因为最小的孩子最容易得到满足,所以先满足最小的孩子。 证明:假设在某次选择中,贪心策略选择给当前满足度最小的孩子分配第 m 个饼干,第 m 个饼干为可以满足该孩子的最小饼干。假设存在一种最优策略,给该孩子分配第 n 个饼干,并且 m < n。我们可以发现,经过这一轮分配,贪心策略分配后剩下的饼干一定有一个比最优策略来得大。因此在后续的分配中,贪心策略一定能满足更多的孩子。也就是说不存在比贪心策略更优的策略,即贪心策略就是最优策略。 @@ -362,434 +802,6 @@ public int maxProfit(int[] prices) { } ``` -## 双指针 - -双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。 - -**有序数组的 Two Sum** - -[Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/) - -```html -Input: numbers={2, 7, 11, 15}, target=9 -Output: index1=1, index2=2 -``` - -题目描述:在有序数组中找出两个数,使它们的和为 target。 - -使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。 - -如果两个指针指向元素的和 sum == target,那么得到要求的结果;如果 sum > target,移动较大的元素,使 sum 变小一些;如果 sum < target,移动较小的元素,使 sum 变大一些。 - -```java -public int[] twoSum(int[] numbers, int target) { - int i = 0, j = numbers.length - 1; - while (i < j) { - int sum = numbers[i] + numbers[j]; - if (sum == target) { - return new int[]{i + 1, j + 1}; - } else if (sum < target) { - i++; - } else { - j--; - } - } - return null; -} -``` - -**两数平方和** - -[633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/) - -```html -Input: 5 -Output: True -Explanation: 1 * 1 + 2 * 2 = 5 -``` - -题目描述:判断一个数是否为两个数的平方和,例如 5 = 12 + 22。 - -```java -public boolean judgeSquareSum(int c) { - int i = 0, j = (int) Math.sqrt(c); - while (i <= j) { - int powSum = i * i + j * j; - if (powSum == c) { - return true; - } else if (powSum > c) { - j--; - } else { - i++; - } - } - return false; -} -``` - -**反转字符串中的元音字符** - -[345. Reverse Vowels of a String (Easy)](https://leetcode.com/problems/reverse-vowels-of-a-string/description/) - -```html -Given s = "leetcode", return "leotcede". -``` - -使用双指针,指向待反转的两个元音字符,一个指针从头向尾遍历,一个指针从尾到头遍历。 - -```java -private final static HashSet vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U')); - -public String reverseVowels(String s) { - int i = 0, j = s.length() - 1; - char[] result = new char[s.length()]; - while (i <= j) { - char ci = s.charAt(i); - char cj = s.charAt(j); - if (!vowels.contains(ci)) { - result[i++] = ci; - } else if (!vowels.contains(cj)) { - result[j--] = cj; - } else { - result[i++] = cj; - result[j--] = ci; - } - } - return new String(result); -} -``` - -**回文字符串** - -[680. Valid Palindrome II (Easy)](https://leetcode.com/problems/valid-palindrome-ii/description/) - -```html -Input: "abca" -Output: True -Explanation: You could delete the character 'c'. -``` - -题目描述:可以删除一个字符,判断是否能构成回文字符串。 - -```java -public boolean validPalindrome(String s) { - int i = -1, j = s.length(); - while (++i < --j) { - if (s.charAt(i) != s.charAt(j)) { - return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j); - } - } - return true; -} - -private boolean isPalindrome(String s, int i, int j) { - while (i < j) { - if (s.charAt(i++) != s.charAt(j--)) { - return false; - } - } - return true; -} -``` - -**归并两个有序数组** - -[88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/) - -```html -Input: -nums1 = [1,2,3,0,0,0], m = 3 -nums2 = [2,5,6], n = 3 - -Output: [1,2,2,3,5,6] -``` - -题目描述:把归并结果存到第一个数组上。 - -需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值 - -```java -public void merge(int[] nums1, int m, int[] nums2, int n) { - int index1 = m - 1, index2 = n - 1; - int indexMerge = m + n - 1; - while (index1 >= 0 || index2 >= 0) { - if (index1 < 0) { - nums1[indexMerge--] = nums2[index2--]; - } else if (index2 < 0) { - nums1[indexMerge--] = nums1[index1--]; - } else if (nums1[index1] > nums2[index2]) { - nums1[indexMerge--] = nums1[index1--]; - } else { - nums1[indexMerge--] = nums2[index2--]; - } - } -} -``` - -**判断链表是否存在环** - -[141. Linked List Cycle (Easy)](https://leetcode.com/problems/linked-list-cycle/description/) - -使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。 - -```java -public boolean hasCycle(ListNode head) { - if (head == null) { - return false; - } - ListNode l1 = head, l2 = head.next; - while (l1 != null && l2 != null && l2.next != null) { - if (l1 == l2) { - return true; - } - l1 = l1.next; - l2 = l2.next.next; - } - return false; -} -``` - -**最长子序列** - -[524. Longest Word in Dictionary through Deleting (Medium)](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/description/) - -``` -Input: -s = "abpcplea", d = ["ale","apple","monkey","plea"] - -Output: -"apple" -``` - -题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回按字典序排序的最大字符串。 - -```java -public String findLongestWord(String s, List d) { - String longestWord = ""; - for (String target : d) { - int l1 = longestWord.length(), l2 = target.length(); - if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) { - continue; - } - if (isValid(s, target)) { - longestWord = target; - } - } - return longestWord; -} - -private boolean isValid(String s, String target) { - int i = 0, j = 0; - while (i < s.length() && j < target.length()) { - if (s.charAt(i) == target.charAt(j)) { - j++; - } - i++; - } - return j == target.length(); -} -``` - -## 排序 - -### 快速选择 - -一般用于求解 **Kth Element** 问题,可以在 O(N) 时间复杂度,O(1) 空间复杂度完成求解工作。 - -与快速排序一样,快速选择一般需要先打乱数组,否则最坏情况下时间复杂度为 O(N2)。 - -### 堆排序 - -堆排序用于求解 **TopK Elements** 问题,通过维护一个大小为 K 的堆,堆中的元素就是 TopK Elements。当然它也可以用于求解 Kth Element 问题,堆顶元素就是 Kth Element。快速选择也可以求解 TopK Elements 问题,因为找到 Kth Element 之后,再遍历一次数组,所有小于等于 Kth Element 的元素都是 TopK Elements。可以看到,快速选择和堆排序都可以求解 Kth Element 和 TopK Elements 问题。 - -**Kth Element** - -[215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/) - -**排序** :时间复杂度 O(NlogN),空间复杂度 O(1) - -```java -public int findKthLargest(int[] nums, int k) { - Arrays.sort(nums); - return nums[nums.length - k]; -} -``` - -**堆排序** :时间复杂度 O(NlogK),空间复杂度 O(K)。 - -```java -public int findKthLargest(int[] nums, int k) { - PriorityQueue pq = new PriorityQueue<>(); // 小顶堆 - for (int val : nums) { - pq.add(val); - if (pq.size() > k) // 维护堆的大小为 K - pq.poll(); - } - return pq.peek(); -} -``` - -**快速选择** :时间复杂度 O(N),空间复杂度 O(1) - -```java -public int findKthLargest(int[] nums, int k) { - k = nums.length - k; - int l = 0, h = nums.length - 1; - while (l < h) { - int j = partition(nums, l, h); - if (j == k) { - break; - } else if (j < k) { - l = j + 1; - } else { - h = j - 1; - } - } - return nums[k]; -} - -private int partition(int[] a, int l, int h) { - int i = l, j = h + 1; - while (true) { - while (a[++i] < a[l] && i < h) ; - while (a[--j] > a[l] && j > l) ; - if (i >= j) { - break; - } - swap(a, i, j); - } - swap(a, l, j); - return j; -} - -private void swap(int[] a, int i, int j) { - int t = a[i]; - a[i] = a[j]; - a[j] = t; -} -``` - -### 桶排序 - -**出现频率最多的 k 个数** - -[347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/) - -```html -Given [1,1,1,2,2,3] and k = 2, return [1,2]. -``` - -设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率,即第 i 个桶中存储的数出现的频率为 i。把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。 - -```java -public List topKFrequent(int[] nums, int k) { - Map frequencyForNum = new HashMap<>(); - for (int num : nums) { - frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1); - } - List[] buckets = new ArrayList[nums.length + 1]; - for (int key : frequencyForNum.keySet()) { - int frequency = frequencyForNum.get(key); - if (buckets[frequency] == null) { - buckets[frequency] = new ArrayList<>(); - } - buckets[frequency].add(key); - } - List topK = new ArrayList<>(); - for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) { - if (buckets[i] != null) { - topK.addAll(buckets[i]); - } - } - return topK; -} -``` - -**按照字符出现次数对字符串排序** - -[451. Sort Characters By Frequency (Medium)](https://leetcode.com/problems/sort-characters-by-frequency/description/) - -```html -Input: -"tree" - -Output: -"eert" - -Explanation: -'e' appears twice while 'r' and 't' both appear once. -So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer. -``` - -```java -public String frequencySort(String s) { - Map frequencyForNum = new HashMap<>(); - for (char c : s.toCharArray()) - frequencyForNum.put(c, frequencyForNum.getOrDefault(c, 0) + 1); - - List[] frequencyBucket = new ArrayList[s.length() + 1]; - for (char c : frequencyForNum.keySet()) { - int f = frequencyForNum.get(c); - if (frequencyBucket[f] == null) { - frequencyBucket[f] = new ArrayList<>(); - } - frequencyBucket[f].add(c); - } - StringBuilder str = new StringBuilder(); - for (int i = frequencyBucket.length - 1; i >= 0; i--) { - if (frequencyBucket[i] == null) { - continue; - } - for (char c : frequencyBucket[i]) { - for (int j = 0; j < i; j++) { - str.append(c); - } - } - } - return str.toString(); -} -``` - -### 荷兰国旗问题 - -荷兰国旗包含三种颜色:红、白、蓝。有这三种颜色的球,算法的目标是将这三种球按颜色顺序正确地排列。 - -它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。 - -

- -**按颜色进行排序** - -[75. Sort Colors (Medium)](https://leetcode.com/problems/sort-colors/description/) - -```html -Input: [2,0,2,1,1,0] -Output: [0,0,1,1,2,2] -``` - -题目描述:只有 0/1/2 三种颜色。 - -```java -public void sortColors(int[] nums) { - int zero = -1, one = 0, two = nums.length; - while (one < two) { - if (nums[one] == 0) { - swap(nums, ++zero, one++); - } else if (nums[one] == 2) { - swap(nums, --two, one); - } else { - ++one; - } - } -} - -private void swap(int[] nums, int i, int j) { - int t = nums[i]; - nums[i] = nums[j]; - nums[j] = t; -} -``` - ## 二分查找 **正常实现** @@ -1065,6 +1077,53 @@ private int binarySearch(int[] nums, int target) { } ``` +## 分治 + +**给表达式加括号** + +[241. Different Ways to Add Parentheses (Medium)](https://leetcode.com/problems/different-ways-to-add-parentheses/description/) + +```html +Input: "2-1-1". + +((2-1)-1) = 0 +(2-(1-1)) = 2 + +Output : [0, 2] +``` + +```java +public List diffWaysToCompute(String input) { + List ways = new ArrayList<>(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (c == '+' || c == '-' || c == '*') { + List left = diffWaysToCompute(input.substring(0, i)); + List right = diffWaysToCompute(input.substring(i + 1)); + for (int l : left) { + for (int r : right) { + switch (c) { + case '+': + ways.add(l + r); + break; + case '-': + ways.add(l - r); + break; + case '*': + ways.add(l * r); + break; + } + } + } + } + } + if (ways.size() == 0) { + ways.add(Integer.valueOf(input)); + } + return ways; +} +``` + ## 搜索 深度优先搜索和广度优先搜索广泛运用于树和图中,但是它们的应用远远不止如此。 @@ -2312,53 +2371,6 @@ private void backtracking(int row) { } ``` -## 分治 - -**给表达式加括号** - -[241. Different Ways to Add Parentheses (Medium)](https://leetcode.com/problems/different-ways-to-add-parentheses/description/) - -```html -Input: "2-1-1". - -((2-1)-1) = 0 -(2-(1-1)) = 2 - -Output : [0, 2] -``` - -```java -public List diffWaysToCompute(String input) { - List ways = new ArrayList<>(); - for (int i = 0; i < input.length(); i++) { - char c = input.charAt(i); - if (c == '+' || c == '-' || c == '*') { - List left = diffWaysToCompute(input.substring(0, i)); - List right = diffWaysToCompute(input.substring(i + 1)); - for (int l : left) { - for (int r : right) { - switch (c) { - case '+': - ways.add(l + r); - break; - case '-': - ways.add(l - r); - break; - case '*': - ways.add(l * r); - break; - } - } - } - } - } - if (ways.size() == 0) { - ways.add(Integer.valueOf(input)); - } - return ways; -} -``` - ## 动态规划 递归和动态规划都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划保存了子问题的解,避免重复计算。 diff --git a/notes/Leetcode-Database 题解.md b/notes/Leetcode-Database 题解.md index 5ab726c5..5b4a3d00 100644 --- a/notes/Leetcode-Database 题解.md +++ b/notes/Leetcode-Database 题解.md @@ -461,7 +461,7 @@ Employee 表: +----+-------+--------+-----------+ ``` -查找所有员工,他们的薪资大于其经理薪资。 +查找薪资大于其经理薪资的员工信息。 ## SQL Schema @@ -924,27 +924,27 @@ VALUES ```sql SELECT s1.id - 1 AS id, - s1.student + s1.student FROM - seat s1 + seat s1 WHERE s1.id MOD 2 = 0 UNION SELECT s2.id + 1 AS id, - s2.student + s2.student FROM - seat s2 + seat s2 WHERE - s2.id MOD 2 = 1 + s2.id MOD 2 = 1 AND s2.id != ( SELECT max( s3.id ) FROM seat s3 ) UNION SELECT s4.id AS id, - s4.student + s4.student FROM - seat s4 + seat s4 WHERE - s4.id MOD 2 = 1 - AND s4.id = ( SELECT max( s5.id ) FROM seat s5 ) + s4.id MOD 2 = 1 + AND s4.id = ( SELECT max( s5.id ) FROM seat s5 ) ORDER BY id; ``` diff --git a/notes/设计模式.md b/notes/设计模式.md index d48d7b36..b8f4dc9b 100644 --- a/notes/设计模式.md +++ b/notes/设计模式.md @@ -98,7 +98,9 @@ public static synchronized Singleton getUniqueInstance() { (三)饿汉式-线程安全 -线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。 +线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。 + +但是直接实例化的方式也丢失了延迟实例化带来的节约资源的好处。 ```java private static Singleton uniqueInstance = new Singleton(); @@ -106,7 +108,7 @@ private static Singleton uniqueInstance = new Singleton(); (四)双重校验锁-线程安全 -uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行。也就是说,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。 +uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。 双重校验锁先判断 uniqueInstance 是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。 @@ -131,7 +133,7 @@ public class Singleton { } ``` -考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程同时执行 if 语句,那么两个线程就会同时进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 `uniqueInstance = new Singleton();` 这条语句,只是先后的问题,也就是说会进行两次实例化,从而产生了两个实例。因此必须使用双重校验锁,也就是需要使用两个 if 语句。 +考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程同时执行 if 语句,那么两个线程就会同时进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 `uniqueInstance = new Singleton();` 这条语句,只是先后的问题,那么就会进行两次实例化,从而产生了两个实例。因此必须使用双重校验锁,也就是需要使用两个 if 语句。 ```java if (uniqueInstance == null) { @@ -157,7 +159,7 @@ uniqueInstance 采用 volatile 关键字修饰也是很有必要的。`uniqueIns 这种方式不仅具有延迟初始化的好处,而且由虚拟机提供了对线程安全的支持。 -```source-java +```java public class Singleton { private Singleton() { @@ -299,7 +301,7 @@ public class Client { ### 意图 -定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化推迟到子类。 +定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。 ### 类图 From bcc266ff354dae6b5fdff7771c4f438399fa4c4c Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Fri, 10 Aug 2018 22:00:21 +0800 Subject: [PATCH 19/53] auto commit --- notes/Leetcode 题解.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index aebe9d72..44f3d9dc 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -57,15 +57,9 @@ ## 双指针 -<<<<<<< HEAD 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。 **有序数组的 Two Sum** -======= -保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。 - -**分配饼干** ->>>>>>> b6156c4247f05d29a65564f0e337545fde70fea1 [Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/) @@ -76,11 +70,7 @@ Output: index1=1, index2=2 题目描述:在有序数组中找出两个数,使它们的和为 target。 -<<<<<<< HEAD 使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。 -======= -给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因为最小的孩子最容易得到满足,所以先满足最小的孩子。 ->>>>>>> b6156c4247f05d29a65564f0e337545fde70fea1 - 如果两个指针指向元素的和 sum == target,那么得到要求的结果; - 如果 sum > target,移动较大的元素,使 sum 变小一些; From f857a0c99675fbe676c54749ccb631ee71b7e324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E4=BC=9F?= <18056981502@163.com> Date: Sun, 12 Aug 2018 22:19:41 +0800 Subject: [PATCH 20/53] List <|.. LinkeList to List <|.. LinkedList --- notes/Java 容器.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes/Java 容器.md b/notes/Java 容器.md index bf1921fc..bd4ecfdb 100644 --- a/notes/Java 容器.md +++ b/notes/Java 容器.md @@ -1080,7 +1080,7 @@ Set <|.. LinkedHashSet SortSet <|.. TreeSet List <|.. ArrayList List <|.. Vector -List <|.. LinkeList +List <|.. LinkedList Queue <|.. LinkedList Queue <|.. PriorityQueue From 9a4f6ea86cffff577870849dcdd5d724295937e9 Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Sun, 12 Aug 2018 22:53:28 +0800 Subject: [PATCH 21/53] auto commit --- notes/HTTP.md | 33 +- notes/Java 容器.md | 61 +- notes/Leetcode 题解.md | 2933 +++++++++++----------- notes/Leetcode-Database 题解.md | 20 +- notes/剑指 offer 题解.md | 281 +-- notes/攻击技术.md | 8 +- notes/数据库系统原理.md | 30 +- notes/算法.md | 30 +- notes/系统设计基础.md | 2 +- notes/设计模式.md | 43 +- pics/VP4n3i8m34Ntd28NQ4_0KCJ2q044Oez.png | Bin 0 -> 21504 bytes 11 files changed, 1719 insertions(+), 1722 deletions(-) create mode 100644 pics/VP4n3i8m34Ntd28NQ4_0KCJ2q044Oez.png diff --git a/notes/HTTP.md b/notes/HTTP.md index 243dc283..537b24fe 100644 --- a/notes/HTTP.md +++ b/notes/HTTP.md @@ -45,7 +45,7 @@ * [二进制分帧层](#二进制分帧层) * [服务端推送](#服务端推送) * [首部压缩](#首部压缩) -* [八、GET 和 POST 的区别](#八get-和-post-的区别) +* [八、GET 和 POST 比较](#八get-和-post-比较) * [作用](#作用) * [参数](#参数) * [安全](#安全) @@ -61,13 +61,13 @@ ## URL -- URI(Uniform Resource Identifier,统一资源标识符) -- URL(Uniform Resource Locator,统一资源定位符) -- URN(Uniform Resource Name,统一资源名称),例如 urn:isbn:0-486-27557-4。 - URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基本都是 URL。 -

+- URI(Uniform Resource Identifier,统一资源标识符) +- URL(Uniform Resource Locator,统一资源定位符) +- URN(Uniform Resource Name,统一资源名称) + +

## 请求和响应报文 @@ -197,7 +197,7 @@ CONNECT www.example.com:443 HTTP/1.1 - **204 No Content** :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。 -- **206 Partial Content** :表示客户端进行了范围请求。响应报文包含由 Content-Range 指定范围的实体内容。 +- **206 Partial Content** :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。 ## 3XX 重定向 @@ -219,7 +219,7 @@ CONNECT www.example.com:443 HTTP/1.1 - **401 Unauthorized** :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。 -- **403 Forbidden** :请求被拒绝,服务器端没有必要给出拒绝的详细理由。 +- **403 Forbidden** :请求被拒绝。 - **404 Not Found** @@ -331,7 +331,7 @@ Set-Cookie: tasty_cookie=strawberry [page content] ``` -客户端之后对同一个服务器发送请求时,会从浏览器中读出 Cookie 信息通过 Cookie 请求首部字段发送给服务器。 +客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。 ```html GET /sample_page.html HTTP/1.1 @@ -382,9 +382,9 @@ Path 标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径 除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。 -Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在内存型数据库中,比如 Redis,效率会更高。 +Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。 -使用 Session 维护用户登录的过程如下: +使用 Session 维护用户登录状态的过程如下: - 用户进行登录时,用户提交包含用户名和密码的表单,放入 HTTP 请求报文中; - 服务器验证该用户名和密码; @@ -499,7 +499,7 @@ If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT ### 1. 短连接与长连接 -当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要断开一次 TCP 连接,连接建立和断开的开销会很大。 +当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。 长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。 @@ -688,7 +688,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer) ### 3. HTTPs 采用的加密方式 -HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证安全性,之后使用对称密钥加密进行通信来保证效率。(下图中的 Session Key 就是对称密钥) +HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)

@@ -717,7 +717,7 @@ HTTPs 的报文摘要功能之所以安全,是因为它结合了加密和认 ## HTTPs 的缺点 - 因为需要进行加密解密等过程,因此速度会更慢; -- 需要支付证书授权的高费用。 +- 需要支付证书授权的高额费用。 ## 配置 HTTPs @@ -727,7 +727,7 @@ HTTPs 的报文摘要功能之所以安全,是因为它结合了加密和认 ## HTTP/1.x 缺陷 - HTTP/1.x 实现简单是以牺牲应用性能为代价的: + HTTP/1.x 实现简单是以牺牲性能为代价的: - 客户端需要使用多个连接才能实现并发和缩短延迟; - 不会压缩请求和响应首部,从而导致不必要的网络流量; @@ -763,7 +763,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见

-# 八、GET 和 POST 的区别 +# 八、GET 和 POST 比较 ## 作用 @@ -870,6 +870,7 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404 - [MDN : HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP) - [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn) - [htmlspecialchars](http://php.net/manual/zh/function.htmlspecialchars.php) +- [Difference between file URI and URL in java](http://java2db.com/java-io/how-to-get-and-the-difference-between-file-uri-and-url-in-java) - [How to Fix SQL Injection Using Java PreparedStatement & CallableStatement](https://software-security.sans.org/developer-how-to/fix-sql-injection-in-java-using-prepared-callable-statement) - [浅谈 HTTP 中 Get 与 Post 的区别](https://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html) - [Are http:// and www really necessary?](https://www.webdancers.com/are-http-and-www-necesary/) diff --git a/notes/Java 容器.md b/notes/Java 容器.md index bf1921fc..af118e4c 100644 --- a/notes/Java 容器.md +++ b/notes/Java 容器.md @@ -25,7 +25,7 @@ ## Collection -

+

### 1. Set @@ -129,12 +129,67 @@ private static final int DEFAULT_CAPACITY = 10; ArrayList 基于数组实现,并且具有动态扩容特性,因此保存元素的数组不一定都会被使用,那么就没必要全部进行序列化。 -保存元素的数组 elementData 使用 transient 修饰,该关键字声明数组默认不会被序列化。ArrayList 重写了 writeObject() 和 readObject() 来控制只序列化数组中有元素填充那部分内容。 +保存元素的数组 elementData 使用 transient 修饰,该关键字声明数组默认不会被序列化。 ```java transient Object[] elementData; // non-private to simplify nested class access ``` +ArrayList 实现了 writeObject() 和 readObject() 来控制只序列化数组中有元素填充那部分内容。 + +```java +private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + elementData = EMPTY_ELEMENTDATA; + + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in capacity + s.readInt(); // ignored + + if (size > 0) { + // be like clone(), allocate array based upon size not capacity + ensureCapacityInternal(size); + + Object[] a = elementData; + // Read in all elements in the proper order. + for (int i=0; i