diff --git a/README.md b/README.md index 9a0a55a7c4cd55fe5f299e908ca87c403f460f28..19a0f3de58627055bf0e8d6f435bb79c278e6352 100644 --- a/README.md +++ b/README.md @@ -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] diff --git a/problems/136.single-number.md b/problems/136.single-number.md index f0285017a783d97b5be174e288bb05d8640153e5..930d2cdd1d27f6cd392f2cb9fb959928ccf11352 100644 --- a/problems/136.single-number.md +++ b/problems/136.single-number.md @@ -1,5 +1,5 @@ - ## 题目地址 + 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! - - diff --git a/thinkings/basic-data-structure.md b/thinkings/basic-data-structure.md new file mode 100644 index 0000000000000000000000000000000000000000..af42dba82bf4aa37142e8822eb2530651a3aebde --- /dev/null +++ b/thinkings/basic-data-structure.md @@ -0,0 +1,41 @@ +# 基础的数据结构 + +## 线性结构 + +### 数组 + +React Hooks + +### 队列 + +message queue + +### 栈 + +call stack, view stack + +### 链表 + +React fiber + +### 非线性结构 + +## 树 + +### 二叉树 + +#### 堆 + +优先级队列 + +#### 二叉查找树 + +### 平衡树 + +database engine + +#### AVL + +#### 红黑树 + +## 图 diff --git a/thinkings/binary-tree-traversal.md b/thinkings/binary-tree-traversal.md new file mode 100644 index 0000000000000000000000000000000000000000..333e41004a700f82be0fe6b977912626ff436fd8 --- /dev/null +++ b/thinkings/binary-tree-traversal.md @@ -0,0 +1,79 @@ +# 二叉树的遍历算法 + +## 概述 + +二叉树作为一个基础的数据结构,遍历算法作为一个基础的算法,两者结合当然是经典的组合了。 +很多题目都会有 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) diff --git a/todo/301.remove-invalid-parentheses.js b/todo/301.remove-invalid-parentheses.js new file mode 100644 index 0000000000000000000000000000000000000000..393a629c8500d33b62348e7b24404d11b5092589 --- /dev/null +++ b/todo/301.remove-invalid-parentheses.js @@ -0,0 +1,48 @@ +/* + * @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) { + +}; + diff --git a/todo/609.find-duplicate-file-in-system.js b/todo/609.find-duplicate-file-in-system.js new file mode 100644 index 0000000000000000000000000000000000000000..2ac09ba5e7593ccd929436e14dfecf5ff4c12ebe --- /dev/null +++ b/todo/609.find-duplicate-file-in-system.js @@ -0,0 +1,87 @@ +/* + * @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) { + +}; +