提交 ca1ecbb2 编写于 作者: L luzhipeng

增加多个模块

上级 f4d52278
......@@ -2,9 +2,23 @@
leetcode 题解,记录自己的 leecode 解题之路。
本仓库目前分为四个部分:
- 第一个部分是 leetcode 经典题目的解析,包括思路,关键点和具体的代码实现。
- 第二部分是对于数据结构与算法的总结
- 第三部分是 anki 卡片, 将 leetcode 题目按照一定的方式记录在 anki 中,方便大家记忆。
- 第四部分是计划, 这里会记录将来要加入到以上三个部分内容
> 只有熟练掌握基础的数据结构与算法,才能对复杂问题迎刃有余
## 传送门
### 简单难度
### leetcode 经典题目的解析
#### 简单难度
- [20. Valid Parentheses](./problems/validParentheses.md)
- [26.remove-duplicates-from-sorted-array](./problems/26.remove-duplicates-from-sorted-array.md)
......@@ -16,7 +30,7 @@ leetcode 题解,记录自己的 leecode 解题之路。
- [283.move-zeroes](./problems/283.move-zeroes.md)
- [349.intersection-of-two-arrays](./problems/349.intersection-of-two-arrays.md)
### 中等难度
#### 中等难度
- [2. Add Two Numbers](https://github.com/azl397985856/leetcode/blob/master/addTwoNumbers.md)
- [3. Longest Substring Without Repeating Characters](https://github.com/azl397985856/leetcode/blob/master/longestSubstringWithoutRepeatingCharacters.md)
......@@ -38,7 +52,22 @@ leetcode 题解,记录自己的 leecode 解题之路。
- [199.binary-tree-right-side-view](./problems/199.binary-tree-right-side-view.md)
- [209.minimum-size-subarray-sum](./problems/209.minimum-size-subarray-sum.md)
### 困难难度
#### 困难难度
- [145.binary-tree-postorder-traversal](./problems/145.binary-tree-postorder-traversal.md)
- [146.lru-cache](./problems/146.lru-cache.md)
### 数据结构与算法的总结
- [basic-data-structure](./thinkings/basic-data-structure.md)
- [binary-tree-traversal](./thinkings/binary-tree-traversal.md)
### anki 卡片
TODO
### 计划
[301.remove-invalid-parentheses]
[609.find-duplicate-file-in-system]
## 题目地址
https://leetcode.com/problems/single-number/description/
## 题目描述
......@@ -11,22 +11,24 @@ Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
```
## 思路
根据题目描述,由于加上了时间复杂度必须是O(n),并且空间复杂度为O(1)的条件,因此不能用排序方法,也不能使用map数据结构。
根据题目描述,由于加上了时间复杂度必须是 O(n),并且空间复杂度为 O(1)的条件,因此不能用排序方法,也不能使用 map 数据结构。
我们可以利用二进制异或的性质来完成,将所有数字异或即得到唯一出现的数字。
## 关键点
1. 异或的性质
两个数字异或的结果`a^b`是将a和b的二进制每一位进行运算,得出的数字。 运算的逻辑是
如果同一位的数字相同则为0,不同则为1
两个数字异或的结果`a^b`是将 a 和 b 的二进制每一位进行运算,得出的数字。 运算的逻辑是
如果同一位的数字相同则为 0,不同则为 1
2. 异或的规律
- 任何数和本身异或则为`0`
- 任何数和0异或是`本身`
- 任何数和 0 异或是`本身`
3. 很多人只是记得异或的性质和规律,但是缺乏对其本质的理解,导致很难想到这种解法(我本人也没想到)
......@@ -48,52 +50,49 @@ Your algorithm should have a linear runtime complexity. Could you implement it w
*
* Given a non-empty array of integers, every element appears twice except for
* one. Find that single one.
*
*
* Note:
*
*
* Your algorithm should have a linear runtime complexity. Could you implement
* it without using extra memory?
*
*
* Example 1:
*
*
*
*
* Input: [2,2,1]
* Output: 1
*
*
*
*
* Example 2:
*
*
*
*
* Input: [4,1,2,1,2]
* Output: 4
*
*
*
*
*/
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
let ret = 0;
for (let index = 0; index < nums.length; index++) {
const element = nums[index];
ret = ret ^ element;
}
return ret;
let ret = 0;
for (let index = 0; index < nums.length; index++) {
const element = nums[index];
ret = ret ^ element;
}
return ret;
};
```
## 延伸
有一个 n 个元素的数组,除了两个数只出现一次外,其余元素都出现两次,让你找出这两个只出现一次的数分别是几,要求时间复杂度为 O(n) 且再开辟的内存空间固定(与 n 无关)。
和上面一样,只是这次不是一个数字,而是两个数字。还是按照上面的思路,我们进行一次全员异或操作,
得到的结果就是那两个只出现一次的不同的数字的异或结果。
我们刚才讲了异或的规律中有一个`任何数和本身异或则为0`, 因此我们的思路是能不能将这两个不同的数字分成两组A和B。
我们刚才讲了异或的规律中有一个`任何数和本身异或则为0`, 因此我们的思路是能不能将这两个不同的数字分成两组 A 和 B。
分组需要满足两个条件.
1. 两个独特的的数字分成不同组
......@@ -104,12 +103,10 @@ var singleNumber = function(nums) {
问题的关键点是我们怎么进行分组呢?
由于异或的性质是,同一位相同则为0,不同则为1. 我们将所有数字异或的结果一定不是0,也就是说至少有一位是1.
由于异或的性质是,同一位相同则为 0,不同则为 1. 我们将所有数字异或的结果一定不是 0,也就是说至少有一位是 1.
我们随便取一个, 分组的依据就来了, 就是你取的那一位是0分成1组,那一位是1的分成一组。
这样肯定能保证`2. 相同的数字分成相同组`, 不同的数字会被分成不同组么。 很明显当然可以, 因此我们选择是1,也就是
我们随便取一个, 分组的依据就来了, 就是你取的那一位是 0 分成 1 组,那一位是 1 的分成一组。
这样肯定能保证`2. 相同的数字分成相同组`, 不同的数字会被分成不同组么。 很明显当然可以, 因此我们选择是 1,也就是
`两个独特的的数字`在那一位一定是不同的,因此两个独特元素一定会被分成不同组。
Done!
# 基础的数据结构
## 线性结构
### 数组
React Hooks
### 队列
message queue
### 栈
call stack, view stack
### 链表
React fiber
### 非线性结构
## 树
### 二叉树
#### 堆
优先级队列
#### 二叉查找树
### 平衡树
database engine
#### AVL
#### 红黑树
## 图
# 二叉树的遍历算法
## 概述
二叉树作为一个基础的数据结构,遍历算法作为一个基础的算法,两者结合当然是经典的组合了。
很多题目都会有 ta 的身影,有直接问二叉树的遍历的,有间接问的。
> 你如果掌握了二叉树的遍历,那么也许其他复杂的树对于你来说也并不遥远了
二叉数的遍历主要有前中后遍历和层次遍历。 前中后属于 DFS,层次遍历属于 BFS。
DFS 和 BFS 都有着自己的应用,比如 leetcode 301 号问题和 609 号问题。
DFS 都可以使用栈来简化操作,并且其实树本身是一种递归的数据结构,因此递归和栈对于 DFS 来说是两个关键点。
BFS 的关键点在于如何记录每一层次是否遍历完成, 我们可以用一个标识位来表式当前层的结束。
下面我们依次讲解:
## 前序遍历
相关问题[144.binary-tree-preorder-traversal](../problems/144.binary-tree-preorder-traversal.md)
前序遍历的顺序是`根-左-右`
思路是:
1. 先将根结点入栈
2. 出栈一个元素,将右节点和左节点依次入栈
3. 重复 2 的步骤
总结: 典型的递归数据结构,典型的用栈来简化操作的算法。
## 中序遍历
相关问题[94.binary-tree-inorder-traversal](../problems/94.binary-tree-inorder-traversal.md)
中序遍历的顺序是 `左-根-右`,根节点不是先输出,这就有一点点复杂了。
1. 根节点入栈
2. 判断有没有左节点,如果有,则入栈,直到叶子节点
> 此时栈中保存的就是所有的左节点和根节点。
3. 出栈,判断有没有右节点,有则入栈,继续执行 2
## 后序遍历
相关问题[145.binary-tree-postorder-traversal](../problems/145.binary-tree-postorder-traversal.md)
后序遍历的顺序是 `左-右-根`
这个就有点难度了,要不也不会是 leetcode 困难的 难度啊。
其实这个也是属于根节点先不输出,并且根节点是最后输出。 这里可以采用一种讨巧的做法,
就是记录当前节点状态,如果 1. 当前节点是叶子节点或者 2.当前节点的左右子树都已经遍历过了,那么就可以出栈了。
对于 1. 当前节点是叶子节点,这个比较好判断,只要判断 left 和 rigt 是否同时为 null 就好。
对于 2. 当前节点的左右子树都已经遍历过了, 我们只需要用一个变量记录即可。最坏的情况,我们记录每一个节点的访问状况就好了,空间复杂度 O(n)
但是仔细想一下,我们使用了栈的结构,从叶子节点开始输出,我们记录一个当前出栈的元素就好了,空间复杂度 O(1), 具体请查看上方链接。
## 层次遍历
层次遍历的关键点在于如何记录每一层次是否遍历完成, 我们可以用一个标识位来表式当前层的结束。
具体做法:
1. 根节点入队列, 并入队列一个特殊的标识位,此处是 null
2. 出队列
3. 判断是不是 null, 如果是则代表本层已经结束。我们再次判断是否当前队列为空,如果不为空继续入队一个 null,否则说明遍历已经完成,我们什么都不不用做
4. 如果不为 null,说明这一层还没完,则将其左右子树依次入队列。
相关问题[102.binary-tree-level-order-traversal](../problems/102.binary-tree-level-order-traversal.md)
/*
* @lc app=leetcode id=301 lang=javascript
*
* [301] Remove Invalid Parentheses
*
* https://leetcode.com/problems/remove-invalid-parentheses/description/
*
* algorithms
* Hard (38.52%)
* Total Accepted: 114.3K
* Total Submissions: 295.4K
* Testcase Example: '"()())()"'
*
* Remove the minimum number of invalid parentheses in order to make the input
* string valid. Return all possible results.
*
* Note: The input string may contain letters other than the parentheses ( and
* ).
*
* Example 1:
*
*
* Input: "()())()"
* Output: ["()()()", "(())()"]
*
*
* Example 2:
*
*
* Input: "(a)())()"
* Output: ["(a)()()", "(a())()"]
*
*
* Example 3:
*
*
* Input: ")("
* Output: [""]
*
*/
/**
* @param {string} s
* @return {string[]}
*/
var removeInvalidParentheses = function(s) {
};
/*
* @lc app=leetcode id=609 lang=javascript
*
* [609] Find Duplicate File in System
*
* https://leetcode.com/problems/find-duplicate-file-in-system/description/
*
* algorithms
* Medium (54.21%)
* Total Accepted: 24.1K
* Total Submissions: 44.2K
* Testcase Example: '["root/a 1.txt(abcd) 2.txt(efgh)","root/c 3.txt(abcd)","root/c/d 4.txt(efgh)","root 4.txt(efgh)"]'
*
* Given a list of directory info including directory path, and all the files
* with contents in this directory, you need to find out all the groups of
* duplicate files in the file system in terms of their paths.
*
* A group of duplicate files consists of at least two files that have exactly
* the same content.
*
* A single directory info string in the input list has the following format:
*
* "root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ...
* fn.txt(fn_content)"
*
* It means there are n files (f1.txt, f2.txt ... fn.txt with content
* f1_content, f2_content ... fn_content, respectively) in directory
* root/d1/d2/.../dm. Note that n >= 1 and m >= 0. If m = 0, it means the
* directory is just the root directory.
*
* The output is a list of group of duplicate file paths. For each group, it
* contains all the file paths of the files that have the same content. A file
* path is a string that has the following format:
*
* "directory_path/file_name.txt"
*
* Example 1:
*
*
* Input:
* ["root/a 1.txt(abcd) 2.txt(efgh)", "root/c 3.txt(abcd)", "root/c/d
* 4.txt(efgh)", "root 4.txt(efgh)"]
* Output:
*
* [["root/a/2.txt","root/c/d/4.txt","root/4.txt"],["root/a/1.txt","root/c/3.txt"]]
*
*
*
*
* Note:
*
*
* No order is required for the final output.
* You may assume the directory name, file name and file content only has
* letters and digits, and the length of file content is in the range of
* [1,50].
* The number of files given is in the range of [1,20000].
* You may assume no files or directories share the same name in the same
* directory.
* You may assume each given directory info represents a unique directory.
* Directory path and file info are separated by a single blank space.
*
*
*
* Follow-up beyond contest:
*
*
* Imagine you are given a real file system, how will you search files? DFS or
* BFS?
* If the file content is very large (GB level), how will you modify your
* solution?
* If you can only read the file by 1kb each time, how will you modify your
* solution?
* What is the time complexity of your modified solution? What is the most
* time-consuming part and memory consuming part of it? How to optimize?
* How to make sure the duplicated files you find are not false positive?
*
*
*/
/**
* @param {string[]} paths
* @return {string[][]}
*/
var findDuplicate = function(paths) {
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册