diff --git a/README-zh-cn.md b/README-zh-cn.md index 2d75f109..fff05be9 100644 --- a/README-zh-cn.md +++ b/README-zh-cn.md @@ -1,6 +1,6 @@ > * 原文地址:[github.com/kdn251/interviews](https://github.com/kdn251/interviews) * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) -* 译者: +* 译者:[王下邀月熊](https://github.com/wxyyxc1992) * 校对者: # Interviews @@ -12,7 +12,6 @@ - [English](./README.md) - ## Table of Contents - [Online Judges](#online-judges) - [Live Coding Practice](#live-coding-practice) @@ -25,7 +24,7 @@ - [Computer Science News](#computer-science-news) - [Directory Tree](#directory-tree) -## Online Judges +## 在线练习 * [LeetCode](https://leetcode.com/) * [Virtual Judge](https://vjudge.net/) * [CareerCup](https://www.careercup.com/) @@ -34,253 +33,214 @@ * [Kattis](https://open.kattis.com/) * [HackerEarth](https://www.hackerearth.com) -## Live Coding Practice +## 在线面试编程 * [Gainlo](http://www.gainlo.co/#!/) * [Refdash](https://refdash.com/) -## Data Structures +## 数据结构 ### Linked List - * A *Linked List* is a linear collection of data elements, called nodes, each - pointing to the next node by means of a pointer. It is a data structure - consisting of a group of nodes which together represent a sequence. - * **Singly-linked list**: linked list in which nodes have pointers to the next node - * **Doubly-linked list**: linked list in which nodes have pointers to *both* the previous node and the next node - * Time Complexity: - * Access: `O(n)` - * Search: `O(n)` - * Insert: `O(1)` - * Remove: `O(1)` + * 链表即是由节点(Node)组成的线性集合,每个节点可以利用指针指向其他节点。它是一种包含了多个节点的、能够用于表示序列的数据结构。 + * **Singly-linked list**: 链表中的节点仅指向下一个节点。 + * **Doubly-linked list**: 链表中的节点不仅指向下一个节点,还指向前一个节点。 + * 时间复杂度: + * 索引: `O(n)` + * 搜索: `O(n)` + * 插入: `O(1)` + * 移除: `O(1)` ### Stack - * A *Stack* is a collection of elements, with two principle operations: *push*, which adds to the collection, and - *pop*, which removes the most recently added element - * Last in, first out data structure (LIFO) - * Time Complexity: - * Access: `O(n)` - * Search: `O(n)` - * Insert: `O(1)` - * Remove: `O(1)` + * 栈是元素的集合,其包含了两个基本操作:push 操作可以用于将元素压入栈,pop 操作可以将栈顶元素移除。 + * 遵循后入先出(LIFO)原则。 + * 时间复杂度: + * 索引: `O(n)` + * 搜索: `O(n)` + * 插入: `O(1)` + * 移除: `O(1)` ### Queue - * A *Queue* is a collection of elements, supporting two principle operations: *enqueue*, which inserts an element - into the queue, and *dequeue*, which removes an element from the queue - * First in, first out data structure (FIFO) - * Time Complexity: - * Access: `O(n)` - * Search: `O(n)` - * Insert: `O(1)` - * Remove: `O(1)` + * 队列是元素的集合,其包含了两个基本操作:enqueue 操作可以用于将元素插入到队列中,而 dequeeu 操作则是将元素从队列中移除。 + * 遵循先入先出原则 (FIFO)。 + * 时间复杂度: + * 索引: `O(n)` + * 搜索: `O(n)` + * 插入: `O(1)` + * 移除: `O(1)` ### Tree - * A *Tree* is an undirected, connected, acyclic graph + * 树即是无向非循环图。 ### Binary Tree - * A *Binary Tree* is a tree data structure in which each node has at most two children, which are referred to as - the *left child* and *right child* - * **Full Tree**: a tree in which every node has either 0 or 2 children - * **Perfect Binary Tree**: a binary tree in which all interior nodes have two children and all leave have the same depth - * **Complete Tree**: a binary tree in which every level *except possibly the last* is full and all nodes in the last - level are as far left as possible + * 二叉树即是每个节点最多包含左子节点与右子节点这两个节点的树形数据结构。 + * **满二叉树**: 树中的每个节点仅包含 0 或 2 个节点。 + * **完美二叉树**: 二叉树中的每个叶节点都拥有两个子节点,并且具有相同的高度。 + * **完全二叉树**: 除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。 ### Binary Search Tree - * A binary search tree, sometimes called BST, is a type of binary tree which maintains the property that the value in each - node must be greater than or equal to any value stored in the left sub-tree, and less than or equal to any value stored - in the right sub-tree - * Time Complexity: - * Access: `O(log(n))` - * Search: `O(log(n))` - * Insert: `O(log(n))` - * Remove: `O(log(n))` + +* 二叉搜索树(BST)是一种特殊的二叉树,其任何节点中的值都会大于或者等于其左子树中存储的值并且小于或者等于其右子树中存储的值。 +* 时间复杂度: + * 索引: `O(log(n))` + * 搜索: `O(log(n))` + * 插入: `O(log(n))` + * 删除: `O(log(n))` Binary Search Tree ### Trie -* A trie, sometimes called a radix or prefix tree, is a kind of search tree that is used to store a dynamic set or associative - array where the keys are usually Strings. No node in the tree stores the key associated with that node; instead, its position - in the tree defines the key with which it is associated. All the descendants of a node have a common prefix of the String associated - with that node, and the root is associated with the empty String. +* 字典树,又称基数树或者前缀树,能够用于存储键为字符串的动态集合或者关联数组的搜索树。树中的节点并没有直接存储关联键值,而是该节点在树中的挂载位置决定了其关联键值。某个节点的所有子节点都拥有相同的前缀,整棵树的根节点则是空字符串。 ![Alt text](/Images/trie.png?raw=true "Trie") ### Fenwick Tree -* A Fenwick tree, sometimes called a binary indexed tree, is a tree in concept, but in practice is implemented as an implicit data - structure using an array. Given an index in the array representing a vertex, the index of a vertex's parent or child is calculated - through bitwise operations on the binary representation of its index. Each element of the array contains the pre-calculated sum of - a range of values, and by combining that sum with additional ranges encountered during an upward traversal to the root, the prefix - sum is calculated -* Time Complexity: - * Range Sum: `O(log(n))` - * Update: `O(log(n))` +* 树状数组又称 Binary Indexed Tree,其表现形式为树,不过本质上是以数组实现。数组中的下标代表着树中的顶点,每个顶点的父节点或者子节点的下标能够通过位运算获得。数组中的每个元素包含了预计算的区间值之和,在整棵树更新的过程中同样会更新这些预计算的值。 +* 时间复杂度: + * 区间求值: `O(log(n))` + * 更新: `O(log(n))` ![Alt text](/Images/fenwickTree.png?raw=true "Fenwick Tree") ### Segment Tree -* A Segment tree, is a tree data structure for storing intervals, or segments. It allows quering which of the stored segments contain - a given point -* Time Complexity: - * Range Query: `O(log(n))` - * Update: `O(log(n))` +* 线段树是用于存放间隔或者线段的树形数据结构,它允许快速的查找某一个节点在若干条线段中出现的次数. +* 时间复杂度: + * 区间查询: `O(log(n))` + * 更新: `O(log(n))` ![Alt text](/Images/segmentTree.png?raw=true "Segment Tree") ### Heap -* A *Heap* is a specialized tree based structure data structure that satisfies the *heap* property: if A is a parent node of -B, then the key (the value) of node A is ordered with respect to the key of node B with the same ordering applying across the entire heap. -A heap can be classified further as either a "max heap" or a "min heap". In a max heap, the keys of parent nodes are always greater -than or equal to those of the children and the highest key is in the root node. In a min heap, the keys of parent nodes are less than -or equal to those of the children and the lowest key is in the root node -* Time Complexity: - * Access: `O(log(n))` - * Search: `O(log(n))` - * Insert: `O(log(n))` - * Remove: `O(log(n))` - * Remove Max / Min: `O(1)` +* 堆是一种特殊的基于树的满足某些特性的数据结构,整个堆中的所有父子节点的键值都会满足相同的排序条件。堆更准确地可以分为最大堆与最小堆,在最大堆中,父节点的键值永远大于或者等于子节点的值,并且整个堆中的最大值存储于根节点;而最小堆中,父节点的键值永远小于或者等于其子节点的键值,并且整个堆中的最小值存储于根节点。 +* 时间复杂度: + * 访问: `O(log(n))` + * 搜索: `O(log(n))` + * 插入: `O(log(n))` + * 移除: `O(log(n))` + * 移除最大值 / 最小值: `O(1)` Max Heap ### Hashing -* *Hashing* is used to map data of an arbitrary size to data of a fixed size. The values return by a hash - function are called hash values, hash codes, or simply hashes. If two keys map to the same value, a collision occurs -* **Hash Map**: a *hash map* is a structure that can map keys to values. A hash map uses a hash function to compute - an index into an array of buckets or slots, from which the desired value can be found. -* Collision Resolution - * **Separate Chaining**: in *separate chaining*, each bucket is independent, and contains a list of entries for each index. The - time for hash map operations is the time to find the bucket (constant time), plus the time to iterate through the list - * **Open Addressing**: in *open addressing*, when a new entry is inserted, the buckets are examined, starting with the - hashed-to-slot and proceeding in some sequence, until an unoccupied slot is found. The name open addressing refers to - the fact that the location of an item is not always determined by its hash value - +* 哈希能够将任意长度的数据映射到固定长度的数据。哈希函数返回的即是哈希值,如果两个不同的键得到相同的哈希值,即将这种现象称为碰撞。 +* **Hash Map**: Hash Map 是一种能够建立起键与值之间关系的数据结构,Hash Map 能够使用哈希函数将键转化为桶或者槽中的下标,从而优化对于目标值的搜索速度。 +* 碰撞解决 + * **链地址法(Separate Chaining)**: 链地址法中,每个桶是相互独立的,包含了一系列索引的列表。搜索操作的时间复杂度即是搜索桶的时间(固定时间)与遍历列表的时间之和。 + * **开地址法(Open Addressing)**: 在开地址法中,当插入新值时,会判断该值对应的哈希桶是否存在,如果存在则根据某种算法依次选择下一个可能的位置,直到找到一个尚未被占用的地址。所谓开地址法也是指某个元素的位置并不永远由其哈希值决定。 ![Alt text](/Images/hash.png?raw=true "Hashing") ### Graph -* A *Graph* is an ordered pair of G = (V, E) comprising a set V of vertices or nodes together with a set E of edges or arcs, - which are 2-element subsets of V (i.e. an edge is associated with two vertices, and that association takes the form of the - unordered pair comprising those two vertices) - * **Undirected Graph**: a graph in which the adjacency relation is symmetric. So if there exists an edge from node u to node - v (u -> v), then it is also the case that there exists an edge from node v to node u (v -> u) - * **Directed Graph**: a graph in which the adjacency relation is not symmetric. So if there exists an edge from node u to node v - (u -> v), this does *not* imply that there exists an edge from node v to node u (v -> u) - +* 图是一种数据元素间为多对多关系的数据结构,加上一组基本操作构成的抽象数据类型。 + * **无向图(Undirected Graph)**: 无向图具有对称的邻接矩阵,因此如果存在某条从节点 u 到节点 v 的边,反之从 v 到 u 的边也存在。 + * **有向图(Directed Graph)**: 有向图的邻接矩阵是非对称的,即如果存在从 u 到 v 的边并不意味着一定存在从 v 到 u 的边。 Graph -## Algorithms +## 算法 -### Sorting +### 排序 -#### Quicksort -* Stable: `No` -* Time Complexity: - * Best Case: `O(nlog(n))` - * Worst Case: `O(n^2)` - * Average Case: `O(nlog(n))` +#### 快速排序 +* 稳定: 否 +* 时间复杂度: + * 最优时间: `O(nlog(n))` + * 最坏时间: `O(n^2)` + * 平均时间: `O(nlog(n))` ![Alt text](/Images/quicksort.gif?raw=true "Quicksort") -#### Mergesort -* *Mergesort* is also a divide and conquer algorithm. It continuously divides an array into two halves, recurses on both the - left subarray and right subarray and then merges the two sorted halves -* Stable: `Yes` -* Time Complexity: - * Best Case: `O(nlog(n))` - * Worst Case: `O(nlog(n))` - * Average Case: `O(nlog(n))` +#### 合并排序 +* 合并排序是典型的分治算法,它不断地将某个数组分为两个部分,分别对左子数组与右子数组进行排序,然后将两个数组合并为新的有序数组。 +* 稳定: 是 +* 时间复杂度: + * 最优时间: `O(nlog(n))` + * 最坏时间: O(nlog(n))` + * 平均时间: `O(nlog(n))` ![Alt text](/Images/mergesort.gif?raw=true "Mergesort") -#### Bucket Sort -* *Bucket Sort* is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket - is then sorted individually, either using a different sorting algorithm, or by recursively applying the bucket sorting algorithm -* Time Complexity: - * Best Case: `Ω(n + k)` - * Worst Case: `O(n^2)` - * Average Case:`Θ(n + k)` +#### 桶排序 +* 桶排序将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。 +* 时间复杂度: + * 最优时间: `Ω(n + k)` + * 最坏时间: `O(n^2)` + * 平均时间:`Θ(n + k)` + ![Alt text](/Images/bucketsort.png?raw=true "Bucket Sort") -#### Radix Sort -* *Radix Sort* is a sorting algorithm that like bucket sort, distributes elements of an array into a number of buckets. However, radix - sort differs from bucket sort by 're-bucketing' the array after the initial pass as opposed to sorting each bucket and merging -* Time Complexity: - * Best Case: `Ω(nk)` - * Worst Case: `O(nk)` - * Average Case: `Θ(nk)` +#### 基数排序 +* 基数排序类似于桶排序,将数组分割到有限数目的桶中;不过其在分割之后并没有让每个桶单独地进行排序,而是直接进行了合并操作。 +* 时间复杂度: + * 最优时间: `Ω(nk)` + * 最坏时间: `O(nk)` + * 平均时间: `Θ(nk)` -### Graph Algorithms +### 图算法 -#### Depth First Search -* *Depth First Search* is a graph traversal algorithm which explores as far as possible along each branch before backtracking -* Time Complexity: `O(|V| + |E|)` +#### 深度优先搜索 +* 深度优先算法是一种优先遍历子节点而不是回溯的算法。 +* 时间复杂度: `O(|V| + |E|)` ![Alt text](/Images/dfsbfs.gif?raw=true "DFS / BFS Traversal") -#### Breadth First Search -* *Breadth First Search* is a graph traversal algorithm which explores the neighbor nodes first, before moving to the next - level neighbors -* Time Complexity: `O(|V| + |E|)` +#### 广度优先搜索 +* 广度优先搜索是优先遍历邻居节点而不是子节点的图遍历算法。 +* 时间复杂度: `O(|V| + |E|)` ![Alt text](/Images/dfsbfs.gif?raw=true "DFS / BFS Traversal") -#### Topological Sort -* *Topological Sort* is the linear ordering of a directed graph's nodes such that for every edge from node u to node v, u - comes before v in the ordering -* Time Complexity: `O(|V| + |E|)` +#### 拓扑排序 +* 拓扑排序是对于有向图节点的线性排序,如果存在某条从 u 到 v 的边,则认为 u 的下标先于 v。 +* 时间复杂度: `O(|V| + |E|)` -#### Dijkstra's Algorithm -* *Dijkstra's Algorithm* is an algorithm for finding the shortest path between nodes in a graph -* Time Complexity: `O(|V|^2)` +#### Dijkstra 算法 +* *Dijkstra 算法* 用于计算有向图中单源最短路径问题。 +* 时间复杂度: `O(|V|^2)` ![Alt text](/Images/dijkstra.gif?raw=true "Dijkstra's") -#### Bellman-Ford Algorithm -* *Bellman-Ford Algorithm* is an algorithm that computes the shortest paths from a single source node to all other nodes in a weighted graph -* Although it is slower than Dijkstra's, it is more versatile, as it is capable of handling graphs in which some of the edge weights are - negative numbers -* Time Complexity: - * Best Case: `O(|E|)` - * Worst Case: `O(|V||E|)` +#### Bellman-Ford 算法 +* **Bellman-Ford 算法**是在带权图中计算从单一源点出发到其他节点的最短路径的算法。 +* 尽管算法复杂度大于 Dijkstra 算法,但是它适用于包含了负值边的图。 +* 时间复杂度: + * 最优时间: `O(|E|)` + - 最坏时间: `O(|V||E|)` ![Alt text](/Images/bellman-ford.gif?raw=true "Bellman-Ford") -#### Floyd-Warshall Algorithm -* *Floyd-Warshall Algorithm* is an algorithm for finding the shortest paths in a weighted graph with positive or negative edge weights, but - no negative cycles -* A single execution of the algorithm will find the lengths (summed weights) of the shortest paths between *all* pairs of nodes -* Time Complexity: - * Best Case: `O(|V|^3)` - * Worst Case: `O(|V|^3)` - * Average Case: `O(|V|^3)` +#### Floyd-Warshall 算法 +* *Floyd-Warshall 算法* 能够用于在无环带权图中寻找任意节点的最短路径。 +* 时间复杂度: + * 最优时间: `O(|V|^3)` + * 最坏时间: `O(|V|^3)` + * 平均时间: `O(|V|^3)` -#### Prim's Algorithm -* *Prim's Algorithm* is a greedy algorithm that finds a minimum spanning tree for a weighted undirected graph. In other words, Prim's find a - subset of edges that forms a tree that includes every node in the graph -* Time Complexity: `O(|V|^2)` +#### Prim 算法 +* **Prim's 算法**是用于在带权无向图中计算最小生成树的贪婪算法。换言之,Prim 算法能够在图中抽取出连接所有节点的边的最小代价子集。 +* 时间复杂度: `O(|V|^2)` ![Alt text](/Images/prim.gif?raw=true "Prim's Algorithm") -#### Kruskal's Algorithm -* *Kruskal's Algorithm* is also a greedy algorithm that finds a minimum spanning tree in a graph. However, in Kruskal's, the graph does not - have to be connected -* Time Complexity: `O(|E|log|V|)` +#### Kruskal 算法 +* **Kruskal 算法**同样是计算图的最小生成树的算法,与 Prim 的区别在于并不需要图是连通的。 +* 时间复杂度: `O(|E|log|V|)` ![Alt text](/Images/kruskal.gif?raw=true "Kruskal's Algorithm") -##Bitmasks -* Bitmasking is a technique used to perform operations at the bit level. Leveraging bitmasks often leads to faster runtime complexity and - helps limit memory usage -* Test kth bit: `s & (1 << k);` -* Set kth bit: `s |= (1 << k);` -* Turn off kth bit: `s &= ~(1 << k);` -* Toggle kth bit: `s ^= (1 << k);` -* Multiple by 2n: `s << n;` -* Divide by 2n: `s >> n;` -* Intersection: `s & t;` -* Union: `s | t;` -* Set Subtraction: `s & ~t;` -* Extract lowest set bit: `s & (-s);` -* Extract lowest unset bit: `~s & (s + 1);` +## 位运算 +* 位运算即是在位级别进行操作的技术,合适的位运算能够帮助我们得到更快地运算速度与更小的内存使用。 +* 测试第 k 位: `s & (1 << k)` +* 设置第 k 位: `s |= (1 << k)` +* 第 k 位置零: `s &= ~(1 << k)` +* 切换第 k 位值: `s ^= ~(1 << k)` +* 乘以 2: `s << n` +* 除以 2: `s >> n` +* 交集: `s & t` +* 并集: `s | t` +* 减法: `s & ~t` +* 交换 `x = x ^ y ^ (y = x)` +* Extract lowest set bit: `s & (-s)` +* Extract lowest unset bit: `~s & (s + 1)` * Swap Values: ``` x ^= y; @@ -288,32 +248,30 @@ or equal to those of the children and the lowest key is in the root node x ^= y; ``` -## Runtime Analysis +## 算法复杂度分析 -#### Big O Notation -* *Big O Notation* is used to describe the upper bound of a particular algorithm. Big O is used to describe worst case scenarios +#### 大 O 表示 +* **大 O 表示** 用于表示某个算法的上限,往往用于描述最坏的情况。 ![Alt text](/Images/bigO.png?raw=true "Theta Notation") -#### Little O Notation -* *Little O Notation* is also used to describe an upper bound of a particular algorithm; however, Little O provides a bound - that is not asymptotically tight +#### 小 O 表示 +* **小 O 表示**用于描述某个算法的渐进上界,不过二者要更为紧密。 -#### Big Ω Omega Notation -* *Big Omega Notation* is used to provide an asymptotic lower bound on a particular algorithm +#### 大 Ω 表示 +* **大 Ω 表示**用于描述某个算法的渐进下界。 ![Alt text](/Images/bigOmega.png?raw=true "Theta Notation") -#### Little ω Omega Notation -* *Little Omega Notation* is used to provide a lower bound on a particular algorithm that is not asymptotically tight +#### 小 ω 表示 +* **Little Omega Notation**用于描述某个特定算法的下界,不过不一定很靠近。 -#### Theta Θ Notation -* *Theta Notation* is used to provide a bound on a particular algorithm such that it can be "sandwiched" between - two constants (one for an upper limit and one for a lower limit) for sufficiently large values +#### Theta Θ 表示 +* **Theta Notation**用于描述某个确定算法的确界。 ![Alt text](/Images/theta.png?raw=true "Theta Notation") -## Video Lectures +## 视频教程 * Data Structures * [UC Berkeley Data Structures](https://www.youtube.com/watch?v=mFPmKGIrQs4&index=1&list=PL-XXv-cvA_iAlnI-BQr9hjqADPBtujFJd) * [MIT Advanced Data Structures](https://www.youtube.com/watch?v=T0yzrZL1py0&list=PLUl4u3cNGP61hsJNdULdudlRL493b-XZf&index=1) @@ -321,15 +279,15 @@ or equal to those of the children and the lowest key is in the root node * [MIT Introduction to Algorithms](https://www.youtube.com/watch?v=HtSuA80QTyo&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=1) * [MIT Advanced Algorithms](https://www.youtube.com/playlist?list=PL6ogFv-ieghdoGKGg2Bik3Gl1glBTEu8c) -## Interview Books +## 面试书籍 * Competitive Programming 3 - Steven Halim & Felix Halim * Cracking The Coding Interview - Gayle Laakmann McDowell * Cracking The PM Interview - Gayle Laakmann McDowell & Jackie Bavaro -## Computer Science News +## 计算机科学与技术资讯 * [Hacker News](https://news.ycombinator.com/) -## Directory Tree +## 文件结构 ``` .