-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5441898
Showing
721 changed files
with
49,788 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# 结构化算法刷题训练指南 | ||
|
||
> 此仓库是 [apachecn/Interview](https://github.com/apachecn/Interview) 的只读备份,用于打包和分发。任何修改请在原仓库上进行。 | ||
> | ||
> **欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远** | ||
* 英文官网: https://leetcode.com | ||
* 中文官网: https://leetcode-cn.com | ||
* [ApacheCN 组织资源](https://docs.apachecn.org/): <https://docs.apachecn.org/> | ||
* **ApacheCN - 面试求职群【724187166】<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=9bcf2fb3985835c9c2f15783ec9c85822e23be1191a6581eaf22f574b5192b19"><img border="0" src="http://data.apachecn.org/img/logo/ApacheCN-group.png" alt="ApacheCN - 面试求职群[724187166]" title="ApacheCN - 面试求职群[724187166]"></a>** | ||
|
||
## 关于刷题 | ||
|
||
``` | ||
刷题可能是目前来说:最有用,也是最没用的东西 | ||
有用只是指:面试最快捷的一种方式 | ||
最没用是指:基本上在工作中用不上 | ||
简单来说;形式主义为主,技术提升为辅,目的就是为了驯服和奴役思维 | ||
会刷题和当年会考试没有本质区别 | ||
我并没有觉得这个是一件值得骄傲的事情 | ||
相反,这恰恰是普通人没用选择的事情 | ||
我吐槽一下: | ||
工作5年,面试还要刷题,写排序,聊一些优化细节和技巧,感觉比较惭愧 | ||
你能写出一个高性能的代码吗?(例如:处理10G,做排序) | ||
你反问:为什么不用GPU和Spark. | ||
他说:。。(他无语) | ||
我觉得大家可能都很无语吧,最无语的应该是前沿的技术吧 | ||
很多时候,基本上你遇到问题百度一下答案就出来了 | ||
工作中你可能没遇到,但是面试你必须背下来,不管会不会 | ||
一个人的好坏,我觉得是在人的性格和搜索能力。 | ||
但是在各大公司的HR和不入流的面试官面前:高学历和强刷题 | ||
技术高低和花的时间有关系,而工作是否录取和高学历和强刷题有关 | ||
``` | ||
|
||
--- | ||
|
||
当然我们得先战胜市场,才能改变市场! | ||
下面正式开始我们刷题教程入门 -- 你准备好了吗? | ||
|
||
## 数据结构 - 排序 | ||
|
||
* 二分查找 | ||
* 冒泡排序 | ||
* 插入排序 | ||
* 选择排序 | ||
* 快速排序 | ||
* 希尔排序 | ||
* 归并排序 | ||
* 基数排序 | ||
|
||
实战入口: <https://interview.apachecn.org/docs/Algorithm/DataStructure> | ||
|
||
## [算法刷题](https://github.com/apachecn/Interview/tree/master/docs/Algorithm/README.md) | ||
|
||
1. [Leetcode](/docs/Algorithm/Leetcode) | ||
- [Python](/docs/Algorithm/Leetcode/Python) | ||
- [Java](/docs/Algorithm/Leetcode/Java) | ||
- [JavaScript](/docs/Algorithm/Leetcode/JavaScript) | ||
- [C++](/docs/Algorithm/Leetcode/C++) | ||
- [ipynb](/docs/Algorithm/Leetcode/ipynb) | ||
- [GO](https://github.com/aQuaYi/LeetCode-in-Go) | ||
- [Golang](https://github.com/kylesliu/awesome-golang-leetcode) | ||
2. [剑指 Offer](/docs/Algorithm/剑指offer) | ||
- [Python](/docs/Algorithm/剑指offer/Python) | ||
- [Scala](/docs/Algorithm/剑指offer/Scala) | ||
- [Java](/docs/Algorithm/剑指offer/Java) | ||
- [JavaScript](/docs/Algorithm/剑指offer/JavaScript) | ||
- [C++](/docs/Algorithm/剑指offer/C++) | ||
3. [数据结构](/docs/Algorithm/DataStructure) | ||
- [Wikipedia: List of Algorithms](https://en.wikipedia.org/wiki/List_of_algorithms) | ||
|
||
## 参与方式 | ||
|
||
> 提交PR基本要求(满足任意一种即可) | ||
* 不一样的思路 | ||
* 优化时间复杂度和空间复杂度,或者解决题目的Follow up | ||
* 有意义的简化代码 | ||
* 未提交过的题目 | ||
|
||
> **案例模版** | ||
[模版 md: 001. Two Sum 两数之和](docs/Algorithm/Leetcode/Python/001._two_sum.md) | ||
[模版页面效果: 001. Two Sum 两数之和](https://interview.apachecn.org/docs/Algorithm/Leetcode/Python/001._two_sum.html) | ||
|
||
## 推荐 LeetCode 网站 | ||
|
||
- [KrisYu的Github](https://github.com/KrisYu/LeetCode-CLRS-Python) | ||
- [kamyu104的Github](https://github.com/kamyu104/LeetCode) | ||
- [数据结构与算法/leetcode/lintcode题解](https://algorithm.yuanbin.me/zh-hans/) | ||
- [Leetcode 讨论区](https://discuss.leetcode.com/) | ||
- [visualgo算法可视化网站](https://visualgo.net/en) | ||
- [Data Structure Visualization](https://www.cs.usfca.edu/~galles/visualization/Algorithms.html) | ||
- [我的算法学习之路 - Lucida](http://zh.lucida.me/blog/on-learning-algorithms/) | ||
- [HiredInTech](https://www.hiredintech.com/) System Design 的总结特别适合入门 | ||
- [mitcc的Github](https://github.com/mitcc/AlgoSolutions) | ||
- [小土刀的面试刷题笔记](http://wdxtub.com/interview/14520594642530.html) | ||
- [nonstriater/Learn-Algorithms](https://github.com/nonstriater/Learn-Algorithms) | ||
- [剑指 Offer 题解](https://github.com/gatieme/CodingInterviews) | ||
- https://github.com/liuchuo/LeetCode | ||
- https://github.com/anxiangSir/SwordforOffer | ||
- https://www.nowcoder.com/ta/coding-interviews?page=1 | ||
- [【小姐姐】刷题博客](https://www.liuchuo.net/about) | ||
- [公瑾的Github](https://github.com/yuzhoujr/leetcode) | ||
- [shejie1993](https://shenjie1993.gitbooks.io/leetcode-python/content/096%20Unique%20Binary%20Search%20Trees.html) | ||
- [编程之法:面试和算法心得](https://legacy.gitbook.com/book/wizardforcel/the-art-of-programming-by-july/details) | ||
- [算法/NLP/深度学习/机器学习面试笔记](https://github.com/imhuay/Interview_Notes-Chinese) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
## 找出数组中重复的数字 | ||
|
||
### 题目描述 | ||
在一个长度为 `n` 的数组里的所有数字都在 `0` 到 `n-1` 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 `7` 的数组 `{2, 3, 1, 0, 2, 5, 3}`,那么对应的输出是重复的数字 `2` 或者 `3`。 | ||
|
||
|
||
### 解法 | ||
#### 解法一 | ||
排序后,顺序扫描,判断是否有重复,时间复杂度为 `O(n²)`。 | ||
|
||
#### 解法二 | ||
利用哈希表,遍历数组,如果哈希表中没有该元素,则存入哈希表中,否则返回重复的元素。时间复杂度为 `O(n)`,空间复杂度为 `O(n)`。 | ||
|
||
#### 解法三 | ||
长度为 `n`,元素的数值范围也为 `n`,如果没有重复元素,那么数组每个下标对应的值与下标相等。 | ||
|
||
从头到尾遍历数组,当扫描到下标 `i` 的数字 `nums[i]`: | ||
- 如果等于 `i`,继续向下扫描; | ||
- 如果不等于 `i`,拿它与第 `nums[i]` 个数进行比较,如果相等,说明有重复值,返回 `nums[i]`。如果不相等,就把第 `i` 个数 和第 `nums[i]` 个数交换。重复这个比较交换的过程。 | ||
|
||
此算法时间复杂度为 `O(n)`,因为每个元素最多只要两次交换,就能确定位置。空间复杂度为 `O(1)`。 | ||
|
||
```java | ||
|
||
/** | ||
* @author bingo | ||
* @since 2018/10/27 | ||
*/ | ||
|
||
public class Solution { | ||
/** | ||
* 查找数组中的重复元素 | ||
* @param numbers 数组 | ||
* @param length 数组长度 | ||
* @param duplication duplication[0]存储重复元素 | ||
* @return boolean | ||
*/ | ||
public boolean duplicate(int[] numbers, int length, int[] duplication) { | ||
if (numbers == null || length < 1) { | ||
return false; | ||
} | ||
for (int e : numbers) { | ||
if (e >= length) { | ||
return false; | ||
} | ||
} | ||
|
||
for (int i = 0; i < length; ++i) { | ||
while (numbers[i] != i) { | ||
if (numbers[i] == numbers[numbers[i]]) { | ||
duplication[0] = numbers[i]; | ||
return true; | ||
} | ||
swap(numbers, i, numbers[i]); | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
private void swap(int[] numbers, int i, int j) { | ||
int t = numbers[i]; | ||
numbers[i] = numbers[j]; | ||
numbers[j] = t; | ||
} | ||
} | ||
``` | ||
|
||
### 测试用例 | ||
1. 长度为 n 的数组中包含一个或多个重复的数字; | ||
2. 数组中不包含重复的数字; | ||
3. 无效测试输入用例(输入空指针;长度为 n 的数组中包含 0~n-1 之外的数字)。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
## 不修改数组找出重复的数字 | ||
|
||
### 题目描述 | ||
在一个长度为 `n+1` 的数组里的所有数字都在 `1` 到 `n` 的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为 `8` 的数组 `{2, 3, 5, 4, 3, 2, 6, 7}`,那么对应的输出是重复的数字 `2` 或者 `3`。 | ||
|
||
|
||
### 解法 | ||
#### 解法一 | ||
创建长度为 `n+1` 的辅助数组,把原数组的元素复制到辅助数组中。如果原数组被复制的数是 `m`,则放到辅助数组第 `m` 个位置。这样很容易找出重复元素。空间复杂度为 `O(n)`。 | ||
|
||
#### 解法二 | ||
数组元素的取值范围是 `[1, n]`,对该范围对半划分,分成 `[1, middle]`, `[middle+1, n]`。计算数组中有多少个(count)元素落在 `[1, middle]` 区间内,如果 count 大于 middle-1+1,那么说明这个范围内有重复元素,否则在另一个范围内。继续对这个范围对半划分,继续统计区间内元素数量。 | ||
|
||
时间复杂度 `O(n * log n)`,空间复杂度 `O(1)`。 | ||
|
||
注意,此方法无法找出所有重复的元素。 | ||
|
||
```java | ||
/** | ||
* @author bingo | ||
* @since 2018/10/27 | ||
*/ | ||
|
||
public class Solution { | ||
/** | ||
* 不修改数组查找重复的元素,没有则返回-1 | ||
* @param numbers 数组 | ||
* @return 重复的元素 | ||
*/ | ||
public int getDuplication(int[] numbers) { | ||
if (numbers == null || numbers.length < 1) { | ||
return -1; | ||
} | ||
|
||
int start = 1; | ||
int end = numbers.length - 1; | ||
while (end >= start) { | ||
int middle = start + ((end - start) >> 1); | ||
|
||
// 调用 log n 次 | ||
int count = countRange(numbers, start, middle); | ||
if (start == end) { | ||
if (count > 1) { | ||
return start; | ||
} | ||
break; | ||
} else { | ||
// 无法找出所有重复的数 | ||
if (count > (middle - start) + 1) { | ||
end = middle; | ||
} else { | ||
start = middle + 1; | ||
} | ||
} | ||
} | ||
return -1; | ||
} | ||
|
||
|
||
/** | ||
* 计算整个数组中有多少个数的取值在[start, end] 之间 | ||
* 时间复杂度 O(n) | ||
* @param numbers 数组 | ||
* @param start 左边界 | ||
* @param end 右边界 | ||
* @return 数量 | ||
*/ | ||
private int countRange(int[] numbers, int start, int end) { | ||
if (numbers == null) { | ||
return 0; | ||
} | ||
int count = 0; | ||
for(int e : numbers) { | ||
if (e >= start && e <= end) { | ||
++count; | ||
} | ||
} | ||
return count; | ||
} | ||
} | ||
``` | ||
|
||
### 测试用例 | ||
1. 长度为 n 的数组中包含一个或多个重复的数字; | ||
2. 数组中不包含重复的数字; | ||
3. 无效测试输入用例(输入空指针)。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
## 二维数组中的查找 | ||
|
||
### 题目描述 | ||
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 | ||
|
||
|
||
### 解法 | ||
从二维数组的右上方开始查找: | ||
- 若元素值等于 `target`,返回 `true`; | ||
- 若元素值大于 `target`,砍掉这一列,即 `--j`; | ||
- 若元素值小于 `target`,砍掉这一行,即 `++i`。 | ||
|
||
也可以从二维数组的左下方开始查找,以下代码使用左下方作为查找的起点。 | ||
|
||
注意,不能选择左上方或者右下方的数字,因为这样无法缩小查找的范围。 | ||
|
||
```java | ||
/** | ||
* @author bingo | ||
* @since 2018/10/27 | ||
*/ | ||
|
||
public class Solution { | ||
/** | ||
* 二维数组中的查找 | ||
* @param target 目标值 | ||
* @param array 二维数组 | ||
* @return boolean | ||
*/ | ||
public boolean find(int target, int[][] array) { | ||
if (array == null) { | ||
return false; | ||
} | ||
int rows = array.length; | ||
int columns = array[0].length; | ||
|
||
int i = rows - 1; | ||
int j = 0; | ||
while (i >= 0 && j < columns) { | ||
if (array[i][j] == target) { | ||
return true; | ||
} | ||
if (array[i][j] < target) { | ||
++j; | ||
} else { | ||
--i; | ||
} | ||
} | ||
return false; | ||
} | ||
} | ||
``` | ||
|
||
### 测试用例 | ||
1. 二维数组中包含查找的数字(查找的数字是数组中的最大值和最小值;查找的数字介于数组中的最大值和最小值之间); | ||
2. 二维数组中没有查找的数字(查找的数字大于/小于数组中的最大值;查找的数字在数组的最大值和最小值之间但数组中没有这个数字); | ||
3. 特殊输入测试(输入空指针)。 |
Oops, something went wrong.