Timeline
Timeline
2025-09-28
Add Introduction
2025-10-18
Add Linear List, Stack, Queue, Array, String
2025-10-20
Add Tree, Graph
2025-11-09
Add DSU (Disjoint Set Union)
2026-03-22
Add Algorithms
This article introduces the basics of data structures and algorithms, covering the logical structure of data (linear and nonlinear structures), storage structures (sequential storage, linked storage, indexed storage, hash storage), as well as the basic concepts and efficiency measurement methods of algorithms. It also discusses in detail the sequential and linked representations of linear lists (including singly linked lists, doubly linked lists, circular linked lists, and static linked lists) and the sequential and linked storage structures of stacks.
Introduction
Logical Structure of Data
The logical structure of data refers to the relationships between data elements, i.e., describing data from a logical perspective. It is independent of data storage and is computer-independent.
- Linear Structure
- Linear List
- Array
- Stack
- Queue
- Linear List
- Non-linear structure
- Set
- Tree structure
- General tree
- Binary tree
- Graph structure
- Directed graph
- Undirected graph
Storage structure of data
Storage structure refers to the representation of data structures in a computer, also known as physical structure
- Sequential storage
Sequential storage means storing logically adjacent elements in storage units that are also physically adjacent;
- Linked storage
Linked storage uses pointers indicating the storage addresses of elements to represent the logical relationships between elements.
- Index storage
Index storage refers to establishing an additional index table while storing element information. Each entry in the index table is called an index item, and the general form of an index item is (key, address).
- Hash storage
Hash storage directly calculates the storage address of an element based on its key, also known as hash storage.
Basic concepts of algorithms
- Finiteness
Finiteness means that an algorithm must always terminate after a finite number of steps, and each step must be completed within finite time.
- Definiteness
Definiteness means that each instruction in an algorithm must have an unambiguous meaning, and for the same input, it must produce the same output.
- Feasibility
Feasibility means that the operations described in an algorithm can be implemented by executing already implemented basic operations a finite number of times.
- Input
Input means that an algorithm has zero or more inputs, which are taken from a specific set of objects.
- Output
Output means that an algorithm has one or more outputs, which are quantities that have a specific relationship with the inputs.
Measurement of algorithm efficiency
Time complexity
Addition rule:
Common asymptotic time complexities
Space complexity
Data structure
Linear list
Definition: A linear list is a finite sequence ofthe same data typen (n>=0) data elements.
A linear list is generally represented as:
Sequential representation of a linear list
The sequential storage of a linear list is also called a sequential list, characterized by the logical order of elements being the same as their physical order. A linear list is aRandom AccessStorage Structure
- C Language Description
1 | // Static Allocation |
- C++ Description
Generally use the standard library vector, or you can customize it
1 | template <typename T> |
- Rust Description
In Rust, generally use the standard library Vec; writing your own requires many unsafe APIs
Basic Operation Time Complexity
| Operation | Best Case | Worst Case | Average Case | Remarks |
|---|---|---|---|---|
| Insert by position | O(1) (at tail) | O(n) (at head) | O(n) | Amortized O(1) for tail insertion |
| Delete by position | O(1) (at tail) | O(n) (at head) | O(n) | Tail deletion O(1) |
| Access by index | O(1) | O(1) | O(1) | Array random access |
| Search (sequential) | O(1) | O(n) | O(n) | If unordered, only sequential search possible |
Linked representation of linear list
Singly linked list
The linked storage of linear list is also called singly linked list.
- C language description
1 | typedef struct LNode{ |
The effect of this C language definition is
| part | meaning |
|---|---|
struct Node { ... }; | defines a structure type with the tag nameNode(i.e.,struct Node) |
LNode | givesstruct Nodean aliastype alias |
*LinkList | givesstruct Node*(i.e., the pointer to this structure) an alias LinkList |
- C++ description
TODO
- Rust description
TODO
head node
usually usehead pointerto identify a singly linked list; when the head pointer is NULL, it indicates an empty list. Additionally, for operational convenience, a node is added before the first node of the singly linked list, calledhead node。
the data field of the head node can be left empty or can store information such as the length of the list.
introducing a head node brings two advantages:
- since the position of the first data node is stored in the pointer field of the head node, operations at the first position of the linked list are consistent with those at other positions, requiring no special handling
- regardless of whether the linked list is empty, its head pointer always points to the head node as a non-null pointer (in an empty list, the pointer field of the head node is NULL), thus unifying the handling of empty and non-empty lists.
creating a singly linked list using head insertion
1 |
|
creating a singly linked list using tail insertion
TODO
doubly linked list
in a singly linked list, there is only one pointer to the successor, allowing traversal only sequentially from the head node. In a doubly linked list, each node has two pointers, prior and next, pointing to the predecessor and successor nodes respectively.
- C language description
1 | typedef struct DNode{ |
- C++ description
TODO
- Rust description
TODO
Circular Linked List
Circular Singly Linked List
The difference between a circular singly linked list and a singly linked list is that the pointer of the last node in the list is not NULL, but instead points to the head node, thus forming a ring.
C Language Description
C++ Description
Rust Description
Circular Doubly Linked List
Compared to a circular singly linked list, the prior pointer of the head node in a circular doubly linked list points to the tail node.
C Language Description
C++ Description
Rust Description
Static Linked List
A static linked list uses an array to describe the chained storage structure of a linear list. Nodes also have a data field and a pointer field next. Unlike the pointers in previous linked lists, the pointer here is the relative address (array index) of the node, also known as a cursor. Similar to a sequential list, a static linked list also requires pre-allocating a contiguous block of memory address space.
For example:
| Index | data | next |
|---|---|---|
| 0 | 4 | |
| 1 | head node | 2 |
| 2 | 10 | 3 |
| 3 | 20 | 5 |
| 4 | 6 | |
| 5 | 30 | -1 |
| 6 | -1 |
1 | 主链表部分: |
C language description
1 |
|
C++ description
Rust description
stack
stack (Stack)is only alloweda linear list that allows insertion or deletion only at one end。
- **top of stack (Top)**the end of the linear list where insertion and deletion are allowed
- **bottom of stack (Bottom)**fixed. The other end where insertion and deletion are not allowed
the characteristics of the stack can be clearly summarized asLast In First Out (LIFO)
mathematical properties of the stack:
The number of possible pop sequences for n distinct elements pushed onto a stack is the nth Catalan number.
The formula is:
Sequential storage structure of a stack
- C language description
1 |
|
- C++ description
TODO
- Rust description
TODO
Shared stack
By utilizing the property that the bottom positions of stacks are relatively fixed, two sequential stacks can share a one-dimensional array space, with the bottoms of the two stacks set at opposite ends of the shared space, and the tops extending toward the middle.
1 | 下标: 0 1 2 3 4 5 6 7 8 9 |
The shared stack is designed to utilize address space more efficiently. Stack overflow occurs if and only if the two stacks are adjacent.
Linked storage structure of a stack
A stack using linked storage is called alinked stack,Linked stackadvantages
- Facilitates multiple stacks sharing storage space and improving efficiency
- No stack overflow situation exists
Linked stacks are typically implemented using a singly linked list, with all operations performed at the head of the list.
- C language description
Here it is specified that the linked stack has no head node
1 | typedef struct LinkNode{ |
- C++ description
TODO
- Rust description
TODO
Classic applications
Bracket matching
Expression evaluation
Converting recursion to stack implementation
Queue
QueueIt is also a linear list with restricted operations, allowing insertion only at one end and deletion only at the other end.
FrontThe end that allows deletion, also known asFront
RearThe end that allows insertion
EnQueueInsert an element at the rear
DeQueueDelete an element from the front
The characteristics of a queue can be simply summarized asFirst In First Out (FIFO)
Sequential storage structure of a queue
- C language description
1 |
|
- C++ description
TODO
- Rust description
Check if the queue is empty
Q.rear == Q.front==0
Determine if the queue is full
Because:
- Enqueue operation: when the queue is not full, first assign the value to the tail element, then increment the tail pointer by 1
- Dequeue operation: when the queue is not empty, first retrieve the head element value, then increment the head pointer by 1
Therefore, it is not possible to use “Q.rear==MaxSize” as the condition for a full queue; the entire problem is solved using a circular queue
Circular queue
The sequential queue is conceived as a circular space, that is, the table storing queue elements is logically regarded as a ring, calledcircular queue
When the head pointerQ.front == MaxSize -1after that, advance one more position to 0
Initialization:Q.front = Q.rear = 0
Head pointer increments by 1:Q.front = (Q.front + 1) % MaxSize
Tail pointer increments by 1:Q.rear = (Q.rear + 1) % MaxSize
Three ways to determine if the queue is full
Sacrificing one unit to distinguish between empty and full queues, using one less queue unit when enqueuing, is a common practice. The convention is to treat ‘the front pointer being at the next position of the rear pointer as the full queue flag’.
- Full queue condition : (Q.rear + 1) % MaxSize == Q.front
- Empty queue condition: (Q.front == Q.rear)
- Number of elements in the queue: (Q.rear - Q.front + MaxSize) % MaxSize
Add a data member to represent the number of elementssize, so that both empty and full queue conditions haveQ.rear == Q.front
- Full queue condition : Q.size == MaxSize
- Empty queue condition: Q.size = 0
- Number of elements in the queue: size
Addtagdata member. When tag is 0, it indicates that a deletion was performed most recently; when tag is 1, it indicates that an insertion was performed most recently.
- Full queue condition: Whentagequals 0, if due to deletionQ.front == Q.rearthen the queue is empty;
- Queue empty condition: Whentagequals 1, due to insertionQ.front == Q.rearthen the queue is full;
- Number of elements in the queue
Linked storage structure of queue
Usually, a linked queue is designed as asingly linked list with a head node.
- C language description
1 | typedef struct LinkNode{ |
- C++ description
TODO
- Rust description
TODO
Deque
A deque is a queue that allows enqueue and dequeue operations at both ends. The two ends of the queue are called the front and the rear.
Input-restricted deque
Insertion and deletion are allowed at one end, but only insertion is allowed at the other end.
Output-restricted deque
Insertion and deletion are allowed at one end, but only deletion is allowed at the other end.
Priority queue (heap)
A heap is a one-dimensional array maintained using the structure of a complete binary tree.
Heaps can be divided intomax heapandmin heap。
Max heap: The value of each node is greater than or equal to the values of its left and right child nodes.
Min heap: The value of each node is less than or equal to the values of its left and right child nodes.
Taking the max heap as an example:
The construction process of a max heap starts from the last non-leaf node and adjusts from bottom to top.
When using an array to represent the sequence to be sorted, the position of the last non-leaf node is:Array length / 2 - 1
Compare the value of the current node with that of the left subtree. If the current node is smaller than the left subtree, swap the current node and the left subtree; after swapping, check whether the left subtree still satisfies the max-heap property, and if not, readjust the subtree structure.
Then compare the value of the current node with that of the right subtree. If the current node is smaller than the right subtree, swap the current node and the right subtree; after swapping, check whether the right subtree still satisfies the max-heap property, and if not, readjust the subtree structure.
When no swapping or adjustment is needed, the max-heap construction is complete.
1 |
|
Classic applications
Level-order traversal
Arrays and special matrices
Array
Most languages provide an array data type.
Compression of special matrices
Symmetric Matrix
- Property: Matrixsatisfies。
- Compression method: Only store theupper or lower triangular part, for example, store the elements of the upper triangle (including the diagonal).
If the matrix is, store the upper triangle row by row:
- Index mapping formula(stored in a one-dimensional array
B[k]):
wherestarts counting from 1.
- Storage space:elements.
Triangular Matrix
- Properties:
- Upper triangular matrix: all elementswhen
- Lower triangular matrix: all elementswhen
- Compression method: store only the non-zero triangular part.
Row-major storage formula for upper triangular matrix:
Row-major storage formula for lower triangular matrix:
- Storage space:elements.
Tridiagonal / Banded Matrix
- Properties: The matrix has non-zero elements only on the main diagonal, super-diagonal, and sub-diagonal, with the rest being 0.
- Compression method: Store three one-dimensional arrays:
A[1..n]stores the main diagonalB[1..n-1]stores the super-diagonalC[1..n-1]stores the sub-diagonal
- Access formula:
- Storage space:elements, compared to a regularsignificantly saves space.
Sparse matrix
The number of non-zero elements t in the matrix is very small relative to the total number of matrix elements s, i.e.,matrix is called asparse matrix。
Storing a sparse matrix using conventional methods is quite wasteful of space, so only the non-zero elements are stored. However, the distribution of non-zero elements is usually very irregular, so the row and column of each non-zero element must also be stored.
Therefore, the non-zero elements along with their corresponding rows and columns form a triple.
Then store this triple according to a certain rule.After compressed storage, the sparse matrix loses the characteristic of random access.。
The triple of a sparse matrix can be stored usingarray storage,or it can usethe orthogonal linked list methodfor storage.
Triple sequential list (array storage)
- Store the non-zero elements in a sparse matrix as triples in row-major or column-major order.
(行标, 列标, 值)。 - Common orders:
- Row-major: Store by rows from top to bottom, and within each row from left to right.
- Column-major: Store by columns from left to right, and within each column from top to bottom.
- Suitable for cases where non-zero elements of the matrix are not frequently modified.
Cross Linked List / Orthogonal List storage
- More suitable for dynamically modified sparse matrices.
- Each non-zero element node contains:
- Value
- Row index
- Column index
- Row pointer (points to the next non-zero element in the same row)
- Column pointer (points to the next non-zero element in the same column)
- Enables fast traversal of rows and columns, suitable for operations like matrix multiplication and transposition.
Disjoint Set Union (DSU)
Disjoint Set Union,DSU / Union-Find

Disjoint Set Union is adata structure that dynamically maintains several disjoint setsand supports two main operations:
| Operations | Function Description |
|---|---|
find(x) | Find ElementxRepresentative of the Set (Root Node) |
union(x, y)/join(x, y) | Merge the Sets of Two Elements |
(Optional)connected(x, y) | Check if Two Elements Belong to the Same Set (i.e.,find(x) == find(y)) |
Data Structure Definition
1 |
|
Tip:
| Technique | Description | Effect |
|---|---|---|
| Path Compression | Duringfind()the operation, point the parent of all nodes on the find path to the root | Significantly reduces tree height, nearly amortized O(1) |
| Union by Rank/Size | Duringunion()the operation, attach the shorter tree under the taller tree | Keeps the tree balanced, further optimizing find efficiency |
Time Complexity
| Operation | Amortized Time Complexity |
|---|---|
find() | Approximately O(1) |
union() | Approximately O(1) |
connected() | Approximately O(1) |
Strictly speaking, it is O(α(n)), but α(n) ≤ 5 for any practical size of n.
String
String pattern matching
The positioning operation of a substring is usually called stringpattern matching, which finds the position of a substring (usually called the pattern string) in the main string.
Naive pattern matching algorithm
Pattern stringpand main strings
1 | S: a b a b c a b c a c b a b |
Code:
1 |
|
Worst case:, whereis the length of the main string,is the length of the pattern string.
- For example, the main string
"aaaaaaab"and the pattern string"aaaab", each match failure requires backtracking multiple characters.
Average case: usually less than the worst case, but may still approach。
KMP algorithm
Recommended excellent explanatory article:
In the naive pattern matching algorithm, each match failure shifts the pattern string (the substring to be matched) one position to the right and starts comparing from the beginning.
Several concepts:
- Prefix: all substrings that include the first character but not the last character
- Suffix: All substrings that include the last letter but not the first letter
- **PM(Partial Match)**Partial match values, i.e., the table below
Below, take “ABCDABD” as the substring to be matched as an example:
| Substring | Prefix set (excluding the full string) | Suffix set (excluding the full string) | Length of the longest equal prefix and suffix |
|---|---|---|---|
| A | (empty) | (empty) | 0 |
| AB | A | B | 0 |
| ABC | A, AB | C, BC | 0 |
| ABCD | A, AB, ABC | D, CD, BCD | 0 |
| ABCDA | A, AB, ABC, ABCD | A, DA, CDA, BCDA | 1(A) |
| ABCDAB | A, AB, ABC, ABCD, ABCDA | B, AB, DAB, CDAB, BCDAB | 2 (AB) |
| ABCDABD | A, AB, ABC, ABCD, ABCDA, ABCDAB | D, BD, ABD, DABD, CDABD, BCDABD | 0 |
Then the PM table is
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| String[i] | A | B | C | D | A | B | D |
| PM | 0 | 0 | 0 | 0 | 1 | 2 | 0 |
- Given the text string “BBC ABCDAB ABCDABCDABDE” and the pattern string “ABCDABD”, now match the pattern string against the text string as shown in the figure below:

- Since character A in the pattern string does not match characters B, B, C, and space in the text string from the start, there is no need to consider the conclusion; simply shift the pattern string right by one position repeatedly until character A in the pattern string matches the 5th character A in the text string:

- Continue matching forward. When the last character D of the pattern string mismatches during matching with the text string, it is obvious that the pattern string needs to be shifted right. But how many positions to shift right? Since the number of matched characters at this point is 6 (ABCDAB), and according to thePMtable, the length value corresponding to character B, which is the previous character of the mismatched character D, is 2. Therefore, based on the previous conclusion, it is known that it needs to be shifted right by 6 - 2 = 4 positions, fromPM[i] = 2That is, restart matching from index 2

We can define anextarray: when the j-th (starting from 0) character of the pattern string fails to match, continue matching from the next[j]-th character of the pattern string.
The next array in KMPThere are two ways to write it:
PM table = prefix function π(i)(also calledlps array,Longest Prefix Suffix)。
In some textbooks, next is equal to PM (lps)
In some textbooks, next is a variant of PM
next[0] = -1(indicating a complete restart of matching)
next[i] = PM[i-1]
1 |
|
Trees and Binary Trees
Terminology
graph TD
A[A] --> B[B]
A --> C[C]
B --> D[D]
B --> E[E]
C --> F[F]
C --> G[G]
E --> H[H]
E --> I[I]
style A fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#9f9,stroke:#333
style F fill:#9f9,stroke:#333
style G fill:#9f9,stroke:#333
style H fill:#9f9,stroke:#333
style I fill:#9f9,stroke:#333
Classification of Nodes
Root Node
The topmost node of a tree.
Example:
Ais the root node.
Parent
The immediate upper-level node of a node.
Example:
B’s parent node isA。
Sibling
Nodes sharing the same parent node are siblings.
Example:
DandEare siblings,FandGare siblings.
Child Node
- Child Node: A node directly connected to a parent node.
- Example:
D、EisB’s child node.
Descendant
- All descendants of a node, including child nodes.
- Example:
H、IisB’s descendant.
Internal Node
- A node that has child nodes.
- Example:
A、B、C、Eare all branch nodes.
Leaf Node
- A node with no children.
- Example:
D、F、G、H、Iare leaf nodes.
Node Properties
Depth of a Node
The length (number of edges) of the path from the root node to this node. (Top-down)
Example:
Adepth 0,Bdepth 1,Ddepth 2.
Height of a Node
The length of the longest path from this node to the deepest leaf node. (Bottom-up)
Example:
BHeight 2 (longest path B→E→H or B→E→I).Level of a Node
Level = Depth + 1
Example: Root node A is level 1, B is level 2.
Degree
- The number of child nodes a node has.
- Example:
Bhas degree 2 (D、E)。
Classification of Trees
Tree of degree m
- The degree of any node is not greater than m
- At least one node has degree m
- Must be a non-empty tree, thus has at least m+1 nodes
m-ary tree
- The degree of any node is not greater than m
- Can be an empty tree
Ordered Tree / Unordered Tree
Ordered Tree: The subtrees of nodes in the tree are ordered from left to right and cannot be swapped, meaning child nodes have a fixed order.
Unordered Tree: The order of child nodes is not important.
Forest
A collection of multiple disjoint trees.
If the root node A is removed, two trees, tree B and tree C, are formed, constituting a forest.
Other Concepts
- Path
- The sequence of nodes traversed from one node to another.
- Example: A→B→E→H is a path.
- Path Length
- The number of edges on the path.
- Example: A→B→E→H, path length = 3.
- Path
Properties of Trees
The number of nodes in a tree equals the sum of all node degrees plus 1.
- The proof is simple: except for the root node, every other node has an edge above it.
A tree of degreehas at mostnodes on the-th level ()
A-ary tree of heighthas at most nodes
A-ary tree withnodes has a minimum height of
- Proof: Under the condition of minimum height, try to make each node havechildren, then:
Binary Tree
A binary tree is an ordered tree
Terminology
Full Binary Tree
graph TD style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#9cf,stroke:#333,stroke-width:1px style C fill:#9cf,stroke:#333,stroke-width:1px style D fill:#9cf,stroke:#333,stroke-width:1px style E fill:#9cf,stroke:#333,stroke-width:1px style F fill:#9cf,stroke:#333,stroke-width:1px style G fill:#9cf,stroke:#333,stroke-width:1px style H fill:#9f9,stroke:#333,stroke-width:1px style I fill:#9f9,stroke:#333,stroke-width:1px style J fill:#9f9,stroke:#333,stroke-width:1px style K fill:#9f9,stroke:#333,stroke-width:1px style L fill:#9f9,stroke:#333,stroke-width:1px style M fill:#9f9,stroke:#333,stroke-width:1px style N fill:#9f9,stroke:#333,stroke-width:1px style O fill:#9f9,stroke:#333,stroke-width:1px A((1)) --> B((2)) A --> C((3)) B --> D((4)) B --> E((5)) C --> F((6)) C --> G((7)) D --> H((8)) D --> I((9)) E --> J((10)) E --> K((11)) F --> L((12)) F --> M((13)) G --> N((14)) G --> O((15))Height, and a binary tree containing nodes is called a full binary tree
In a full binary tree, every node except leaf nodes has degree 2
A full binary tree can be numbered in level order, for a node numbered:
Left child number:
Right child number:
Parent node number:
complete binary tree
graph TD style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#9cf,stroke:#333,stroke-width:1px style C fill:#9cf,stroke:#333,stroke-width:1px style D fill:#9cf,stroke:#333,stroke-width:1px style E fill:#9cf,stroke:#333,stroke-width:1px style F fill:#9cf,stroke:#333,stroke-width:1px style G fill:#9cf,stroke:#333,stroke-width:1px style H fill:#9f9,stroke:#333,stroke-width:1px style I fill:#9f9,stroke:#333,stroke-width:1px style J fill:#9f9,stroke:#333,stroke-width:1px style K fill:#9f9,stroke:#333,stroke-width:1px style L fill:#9f9,stroke:#333,stroke-width:1px A((1)) --> B((2)) A --> C((3)) B --> D((4)) B --> E((5)) C --> F((6)) C --> G((7)) D --> H((8)) D --> I((9)) E --> J((10)) E --> K((11)) F --> L((12))- with height, havinga binary tree with nodes, if and only if each of its nodes corresponds one-to-one with nodes numbered 1 to n in a full binary tree of height, it is called a complete binary tree
- If , then nodeis a branch node
- Leaf nodes can only appear in the two largest levels, and for the largest level, leaf nodes are all arranged in the leftmost positions of that level.
- If there is a node with degree 1, there can be at most one, and that node has only a left child and no right child.
- After numbering by level order, once a node (numbered) is a leaf node or has only a left child, then nodes with numbers greater thanare all leaf nodes
- Ifis odd, then every branch node has both left and right children; ifis even, then the branch node with the largest number (numbered) only has a left child, no right child; the remaining nodes have both left and right children
- Of the two subtrees of a complete binary tree (the left and right subtrees of the root node), at least one is a full binary tree
Binary Search Tree
- All keys in the left subtree are less than the root node’s key, and all keys in the right subtree are greater than the root node’s key; both the left and right subtrees are themselves binary search trees.
Balanced Binary Tree
- On the treeThe difference in depth between the left subtree and right subtree of any node does not exceed 1

Properties
The number of leaf nodes in a non-empty binary tree equals the number of nodes with degree 2 plus 1, i.e.,
On a non-empty binary tree, the -th level has at mostnodes ()
A binary tree of heighthas at mostnodes ()
withnodescomplete binary treehas height or
forcomplete binary treenode numbering, the following relationships hold
| Item | 1-based numbering(root=1) | 0-based numbering(root=0) |
|---|---|---|
| left child | ||
| right child | ||
| Parent node | ||
| Condition for having at least a left child | ||
| Condition for right child existence | ||
| Leaf node condition | or | |
| Condition for having only a left child | and | |
| Depth (root level = 1) | ||
| Depth (root level = 0) |
Storage structure
- Sequential storage structure
Array storage, stored in the manner of a complete binary tree, using 0 or -1 to represent empty nodes.
- Linked storage
It is easy to verify that in a binary linked list containingnodes, there arenull pointer fields
n nodes, 2n pointer fields, n-1 nodes have a pointer pointing to themselves, so there are n+1 null pointer fields
binary tree traversal
preorder traversal
visit the root node first, then traverse the left subtree, then traverse the right subtree
recursive implementation
1 | void PreOrder(BiTree T){ |
non-recursive implementation
1 | void PreOrder(BiTree T){ |
description in Rust
1 | // Definition for a binary tree node. |
inorder traversal
visit the left subtree first, then the root node, then the right subtree
Recursive approach
1 | void InOrder(BiTree T){ |
Non-recursive approach
- Push the left children of the root node onto the stack in sequence until the left child is null, indicating that a node ready to be output has been found
- Pop and visit the top element of the stack; if it has a right child, continue with step 1; otherwise, continue with step 2
1 | void InOrder(BiTree T){ |
Post-order traversal
Visit the left subtree first, then the right subtree, then the root node
Recursive approach
1 | void PostOrder(BiTree T){ |
Non-recursive approach
- Push the left children of the root onto the stack in sequence until the left child is null
- Read the top element of the stack: if its right child is not null and has not been visited, perform step 1 on the right subtree; otherwise, pop and visit the top element
For the top element to be popped and visited, either its right subtree is null or its right subtree has already been visited (at which point the left subtree has long been visited). Therefore, we need an auxiliary pointer to indicate the most recently visited node
1 | void PostOrder(BiTree T){ |
In post-order traversal, when a node is about to be visited, the nodes in the stack are all the nodes on the path from the root to the current node
Non-recursive approaches for three traversals
1 |
|
Level-order traversal
Traverse from the first layer to the last layer, from left to right
1 | void LevelOrder(BiTree T){ |
If you need to record or perform some operations when each layer is fully visited:
1 | /** |
Morris traversal
Morris traversal uses the idea of threaded binary trees. In the Morris method, there is no need to allocate additional pointers for each node to point to its predecessor and successor; it only needs to utilizethe left and right null pointers in leaf nodesto point to the predecessor or successor node under a certain order traversal.
graph TD
subgraph 图2
B1[1]
B2[2]
B3[3]
B4[4]
B5[5]
B6[6]
B7[7]
B1 --> B2
B1 --> B3
B2 --> B4
B2 --> B5
B3 --> B6
B3 --> B7
B4 -.-> B2:::cur2
B5 -.-> B1:::cur1
B6 -.-> B3:::curn
end
subgraph 图1
A1[1] --> A2[2]
A1 --> A3[3]
A2 --> A4[4]
A2 --> A5[5]
A3 --> A6[6]
A3 --> A7[7]
endThe overall idea of Morris is to start from a certain root node,find the rightmost node of its left subtree, and then connect it to this root node
We can see from Figure 2 that after such connection, the cur pointer can traverse from one node to the next completely, traversing the entire tree until node 7 has no right pointer. Code example:
1 | /** |
Graph
Terminology
Basic Concepts
| Terminology | Explanation |
|---|---|
| Directed Graph | Edges in the graph have directions, such as |
| Undirected Graph | Edges have no direction, such as, indicating a bidirectional relationship |
Classification by Edge Structure
| Terminology | Explanation |
|---|---|
| Simple Graph | Does not allowself-loops(connecting a vertex to itself) andmultiple edges(multiple edges between two vertices) |
| Multigraph | Allows self-loops and multiple edges |
Special Graphs
| Term | Explanation |
|---|---|
| Complete Graph | There is an edge between any two vertices. An undirected complete graph is denoted as, withedges |
| Subgraph | A graph formed by taking a subset of vertices and edges from the original graph |
Graph Connectivity
| Term | Explanation |
|---|---|
| Connected | In an undirected graph, any two vertices are connected by a path |
| Connected Graph | The graph is entirely connected |
| Connected Component | A maximal connected subgraph in an undirected graph (a connected piece that cannot be enlarged) |
| Strongly Connected Graph | In a directed graph, any two verticesandThere exist mutually reachable paths |
| Strongly Connected Component | The largest strongly connected subgraph in a directed graph |
Tree-related
| Terminology | Explanation |
|---|---|
| Spanning Tree | In a connected undirected graph, a tree that includes all vertices with the minimum number of edges () |
| Spanning Forest | For a disconnected graph, a collection of spanning trees generated from each connected component |
Properties of vertices and edges
| Terminology | Explanation |
|---|---|
| Degree of a vertex | Degree (number of edges connected to a vertex in an undirected graph) |
| In-degree | Number of edges pointing to the vertex in a directed graph |
| Out-degree | Number of edges pointing away from the vertex in a directed graph |
| Weight of an edge | Additional value attached to an edge (e.g., distance, time, cost) |
| Network | Weighted graph (graph with edge weights), also called network |
| Dense Graph | Graph with many edges, a vague concept |
| Sparse Graph | Graph with few edges, a vague concept |
Path and Distance
| Terminology | Explanation |
|---|---|
| Path | A sequence of vertices where any two adjacent vertices are connected by an edge |
| Path length | The number of edges (or sum of weights) on the path |
| Cycle | A path with the same start and end point |
| Simple path | Vertices in the path are not repeated |
| Simple cycle | In a cycle, vertices other than the start and end are not repeated |
| Distance | The length of the shortest path between two vertices |
Storage
Adjacency matrix method
Undirected graph:
- If
iandjhave an edge:Edge[i][j] = Edge[j][i] = 1 - If no edge:
Edge[i][j] = Edge[j][i] = 0
Directed graph:
- If there is
i → j’s edge:Edge[i][j] = 1 - If not:
Edge[i][j] = 0
Network (weighted graph):
If
i → j’s weight isw, thenEdge[i][j] = wWhen there is no edge, it is generally set to
∞(or a very large number)C language description
1 |
|
- C++ description
1 |
|
adjacency list method
- C language description
1 |
|
- C++ Description
Orthogonal List Method
1 |
|
Adjacency Multilist
The adjacency multilist is another linked storage structure for undirected graphs
1 | typedef struct ENode { |
Graph traversal
Breadth-First Search
1 | bool visited[MAX_VERTEX_NUM]; |
If the graph is unweighted, BFS can be used to solve the single-source shortest path problem, mainly leveraging the property that breadth-first traversal visits vertices in order of increasing distance.
Depth-First Search
Recursive form
1 | bool visited[MAX_VERTEX_NUM]; |
Non-recursive form
1 | void DFS_Non_RC(AGraph &G, int v){ |
Minimum spanning tree
Prim’s algorithm
Idea: Start from a point, each time selectthe edge with the smallest costadd the new vertex to the spanning tree
more suitable for:dense graphs(adjacency matrix)
Kruskal’s algorithm
Idea: Sort all edges of the graph by weight, select edges from smallest to largest, as long asno cycle is formedthen select
suitable for:sparse graphs
Using Union-FindAvoid forming cycles
Shortest path
Dijkstra’s algorithm
Single-source shortest path problem
Floyd’s algorithm
Shortest paths between all pairs of vertices
Topological sorting
Take the following problem as an example:
1 |
|
Critical Path
Hash
Reference Article:
Hash Table (Hash Table) also known as a hash table is a data structure that uses key-value pairs (Key-Value Pair) to store data, andmaps keys to specific positions in an array via a hash function, enabling efficient search, insertion, and deletion operations.
Concept
Storage Structure: A hash table typically consists of an array and a hash function. Each element of the array is called a bucket, which can store one or more key-value pairs
Hash Function: The hash function converts a key into an array index (i.e., an integer)
Hashing: is the process of converting input data (usually of arbitrary length) into a fixed-length output (an index within the array range) through a hash function
Hash Collision: When different keys are mapped to the same index by the hash function, a hash collision occurs. Common methods to resolve hash collisions include chaining and open addressing
Load Factor:The ratio of the number of elements stored in the hash table to the size of the array (total number of slots)
- The size of the hash table (number of slots) is fixed, but the number of stored elements can exceed the number of slots
- The load factor indicates the utilization efficiency of the hash table space.A higher load factor means more elements are stored in the table, with higher space utilization
- Whenthe load factor increases (approaching 1 or higher), the lookup efficiency of the hash table may decrease, especially when using open addressing, conflict resolution requires more probing steps
- When using chaining, an increase in the load factor leads to longer linked lists, thereby increasing the average search time
- In dynamic hash tables, when the load factor exceeds a certain threshold (e.g., 0.75), it typically triggers rehashing to reduce collisions and improve performance
- If the load factor is too low, it may lead to shrinking to save space
- Ideal load factor:
- Open addressing: The ideal load factor is typically below 1, recommended between 0.5 and 0.75 to balance space utilization and lookup efficiency.
- Chaining: The load factor can exceed 1 because multiple elements can be stored in the same slot. Typically, a load factor between 0.7 and 1.0 is a good choice, but it can be higher depending on the impact of chain length on performance.
Rehashing: When the load factor of the hash table exceeds a set threshold, rehashing may be needed. Rehashing typically involves creating a larger array and recalculating the hash values of all keys to map them into the new array.
Shrinking: Shrinking refers to reducing the capacity of the hash table when the amount of data decreases to a certain level, to save space and improve memory utilization efficiency.
Hash function
A hash function converts a key into an array index (i.e., an integer). A good hash function should have the following advantages:
Fast computation: The advantage of hash tables lies in efficiency, so quickly obtaining the corresponding hashCode is very important.
Uniform distribution: In hash tables, whether using chaining or open addressing, when multiple elements map to the same position, efficiency is affected. An excellent hash function should map elements to different positions as much as possible, allowing elements to be uniformly distributed in the hash table.
Key type
Ultimately, a hash function is about converting keyskeyConverted to an index value, it can serve as a keykeyThere are many types that can serve as keys: numbers, strings, objects, etc. Below, we mainly discuss strings as keys becauseHash table keys are typically implemented as strings, mainly for the following reasons:
Consistency: Using strings as keys provides a uniform way to handle different types of keys. Even numbers and other types are ultimately converted to strings for storage
Hash function: Hash tables use a hash function to map keys to array indices. Strings are generally easier to handle because they can be directly hashed, while other types (such as objects) may require more processing steps
Ease of comparison: Strings have clear comparison rules, making lookup, insertion, and deletion operations simpler and more efficient
Space efficiency: In many languages, storing strings as keys is typically more compact than objects or other complex types, reducing memory usage
Flexibility: Strings can represent various types of information and easily adapt to different scenarios, such as database indexes, field names, etc.
There are two methods for a hash function to convert a string into a number:
Method one:Summing the ASCII values of the characters, the problem is that many keys may end up with the same value, for example
was/tin/give/tend/moan/tickboth are 43Method two:Multiplying each character’s ASCII value of the key by a constant, the resulting number can basically guarantee its uniqueness (explained below), the repetition rate with other words is greatly reduced, but the problem is that the obtained value is too large. Since this value is to be used as an index, creating such a large array is meaningless.
In fact, numbers greater than 10 that we commonly use can be represented by a product of powers to express their uniqueness. For example:
7654 = 7*10³ + 6*10² + 5*10 + 4, words can also be represented using this scheme. For example:cats = 3*27³ + 1*27² + 20*27 + 17= 60337, 27 because there are 27 letters.Then, for the problem of the obtained index being too large, a compression algorithm emerges, which compresses the huge integer range obtained from the product of powers scheme into an acceptable array range. A simple method is to use the modulo operator, which gives the remainder when one number is divided by another. Array indices are limited, for example from 0 to n-1 (where n is the acceptable array length). By applying the modulo operation, they can be constrained within this range.
Horner’s Rule
The method used above when calculating the hash value:cats = 3*27³ + 1*27² + 20*27 + 17= 60337, we can abstract it into an expression:a(n)x^n + a(n-1)x^(n-1) +... + a(1)x + a(0)
Number of multiplications:
n + (n-1) +... + 1 = n(n + 1)/2Number of additions:
ntimes- Time complexity:
O(N²)
- Time complexity:
Through transformation, a much faster algorithm can be obtained, which is an efficient algorithm for solving this type of evaluation problem.Horner’s Rule(Horner’s Method), known in China asQin Jiushao’s algorithm, the core of Horner’s rule is to rewrite an ordinary polynomial into nested form. Taking a cubic polynomial as an example, the common factor (x) is gradually extracted to reduce computation. The derivation process is as follows:
Original polynomial form(cubic polynomial):
- Step 1: Extract the common factor (x) from the first two terms:
- Step 2: Extract the common factor (x) again from the part inside the parentheses:
- Step 3: Combine the remaining terms to form the final nested form:
General form of Horner’s rule (n-degree polynomial) For any (n)-degree polynomial , it can be uniformly transformed into:
where:
- Number of multiplications:
ntimes - Number of additions:
ntimes - Time complexity: from
O(N²)reduced toO(N)
uniform distribution
When designing a hash table, the case of mapping to the same index value has already been handled: chaining or open addressing. However, both methods aim to improve efficiency, and the best scenario is to have data uniformly distributed in the hash table. Therefore,**it is necessary to use prime numbers wherever constants are used,**such as the length of the hash table and the base of the N-th power.
Why does using prime numbers make the hash table distribution more uniform?
Because the result of multiplying a prime number with other numbers is more likely to produce unique results compared to other numbers, reducing hash collisions.
For example, the base of the N-th power in Java’s HashMap is chosen as 31, and commonly used numbers are 31 or 37, which are derived from long-term observation of distribution results.
Hash Collision
When different keys are mapped to the same index by the hash function, a hash collision occurs. Common methods to resolve hash collisions include chaining and open addressing.
Chaining
Chaining is a common method for resolving collisions (also known as separate chaining). Each bucket of the hash table can store multiple elements. When multiple keys are hashed to the same index, chaining stores these elements in a linked list or other data structure.

Principle
of chaining**The core idea is to treat each array element as a bucket, storing multiple key-value pairs within the bucket.**This is usually implemented using linked lists or arrays.
Once a duplicate is found, insert the duplicate element into**the head or tail of the linked list.**That’s all.
When querying, first locate the corresponding position based on the hashed index value, thenretrieve the linked listand sequentially search for the desired data.
Efficiency
- When implementing a hash table using the chaining method, the process of finding an element is divided into two parts:
- Calculate the hash value and locate the slot: This step is a constant-time operation, typically 1 operation, independent of the linked list length.
- Traverse the linked list to find the element: If multiple elements are in the same slot, the hash table searches the linked list of that slot. The average number of searches is half the linked list length, typically loadFactor / 2.
- Therefore, a successful search may only need to examine half the linked list: 1 + loadFactor/2, while an unsuccessful search may need to traverse the entire linked list to determine failure: 1 + loadFactor.
- The chaining method is relatively more efficient than the open addressing method, so it is more commonly used in real development. It does not cause a sharp performance drop after adding an element; for example, Java’s HashMap uses the chaining method.
- When implementing a hash table using the chaining method, the process of finding an element is divided into two parts:

Open addressing method
of open addressing methodThe main working method is to find the next empty slot in the array to store the conflicting element when a hash collision occurs, there are three ways to probe empty slots:
Linear probing
- Linear probing (
Linear Probing) checks the next empty slot each time a collision occursindex = (hashFunc(key) + i) % tableSizewhere i is the number of collisions - Efficiency

Relationship between expected number of probes and load factor Problem: Linear probing has a serious issue called clustering
For example, when inserting 22-23-24-25-26 into an empty table, it means indices 0-1-2-3-4 all have elements; this series of filled cells is called clustering
Clustering affects the performance of the hash table in insertion, query, and deletion. For example, inserting 38 would find that consecutive cells cannot store data, requiring multiple probes during the process
- Linear probing (
Quadratic probing
- Quadratic probing (
Quadratic Probing) Determine the position of the next slot based on the square of the number of collisionsindex = (hashFunc(key) + i^2) % tableSize - Optimizing linear problems:
- Linear probing can be seen as a step size of
1probing, for example, starting from the index valuexthen linear testing isx+1,x+2,x+3probing sequentially - Quadratic probing optimizes the step size, for example, starting from the index value
xstartingx+1²,x+2²,x+3², so that it can probe a longer distance at once, better avoiding the impact of clustering
- Linear probing can be seen as a step size of
- Efficiency:

Performance of quadratic probing and rehashing - Problem:
- Quadratic probing still has problems, for example, if consecutive insertions are
32-112-82-2-192, then the step sizes are the same when accumulating sequentially - That is, in this caseit will cause a clustering with different step sizes, which still affects efficiency
- Quadratic probing still has problems, for example, if consecutive insertions are
- Quadratic probing (
Rehashing method
- Rehashing (
Double Hashing) uses a second hash function to calculate the step size and determine the position of the next slotindex = (hashFunc1(key) + i \* (constant - (hashFunc2(key) % constant))) % tableSize - Optimizing the quadratic probing problem:
- The quadratic probing algorithm generates a fixed step size sequence: 1-4-9-16 and so on, while the rehashing method uses another hash function to hash the key again and uses the result of this hashing as the step size
- The second hashing must have the following characteristics:
- It must be different from the first hash function (do not reuse the previous hash function, otherwise the result will still be the original position)
- It must not output 0 (otherwise there will be no step size, each probe will stay in place, and the algorithm will enter an infinite loop)
- Computer experts have designed a well-functioning hash function:
stepSize = constant - (hanshFunc(key) % constant), where constant is a prime number and smaller than the array capacity
- Efficiency

Performance of quadratic probing and rehashing method - Rehashing (
Expansion/Shrinkage
- Expansion: As the amount of data increases, the bucket corresponding to each index becomes longer, leading to reduced efficiency. Therefore, when appropriate, the array is expanded, for example, by doubling its size.
Expansion can simply double the capacity, but in this case, all data items must be modified simultaneously (by re-calling the hash function to obtain different positions). For example, a data item with hashCode = 12 is placed at index = 4 when arraySize = 8, and at index = 12 when arraySize = 16.
- Shrinkage: When the load factor of the hash table (the ratio of the number of elements to the hash table capacity) falls below a certain threshold, shrinkage is considered to save space and improve memory utilization efficiency.
During shrinkage, the hash table capacity is typically reduced to half of its current capacity, and the positions of all existing elements are recalculated and reassigned.
When to expand/shrink?
A common scenario isloadFactor > 0.75expansion is performed when the load factor exceeds a certain value. For example, Java’s hash table expands when the load factor is greater than 0.75.
A lower load factor threshold is usually set, such as 0.25, below which shrinkage is triggered. However, excessive shrinkage should be avoided: a small, reasonable minimum capacity, such as 7 or 8, is typically set to ensure the hash table maintains a certain capacity even when there are few elements, thereby preventing frequent expansion and shrinkage.
Implementation of Hash Table
1 |
|
Common algorithms
Hash
| Problem | Link |
|---|---|
| P1 Two Sum✨✨✨ | |
| P49 Group Anagrams | |
| P128 Longest Consecutive Sequence✨✨✨ | |
| P383 Ransom Note | |
| P205 Isomorphic Strings | |
| P290 Word Pattern | |
| P242 Valid Anagram | |
| P49 Group Anagrams | |
| P202 Happy Number | |
| P219 Contains Duplicate II✨✨✨ | |
| P966 Vowel Spellchecker | |
| P3484 Design Spreadsheet | |
| P380 Insert Delete GetRandom O(1)✨✨✨ | |
| P3289 The Troublemaker in Number Town | |
| P13 Roman to Integer |
Two Pointers
Fast and Slow Pointers
| Title | Link |
|---|---|
| P234 Palindrome Linked List | |
| P142 Linked List Cycle II | |
| P80 Remove Duplicates from Sorted Array II ✨✨✨ | |
| P287 Find the Duplicate Number ✨✨✨ | |
| P19 Remove Nth Node From End of List | |
| P160 Intersection of Two Linked Lists |
Left and Right Pointers
| Problem | Link |
|---|---|
| P283 Move Zeroes | |
| P125 Valid Palindrome | |
| P27 Remove Element | |
| P167 Two Sum II - Input Array Is Sorted | |
| P88 Merge Sorted Array | |
| P392 Is Subsequence | |
| P75 Sort Colors | |
| P31 Next Permutation | |
| P15 3Sum ✨✨✨ | |
| P11 Container With Most Water ✨✨✨ | |
| P611 Valid Triangle Number | |
| P42 Trapping Rain Water ✨✨✨ |
Linked List
| Problems | Link |
|---|---|
| P3217 Remove Nodes from Linked List Present in Array | |
| P141 Linked List Cycle | |
| P2 Add Two Numbers | |
| P21 Merge Two Sorted Lists | |
| P138 Copy List with Random Pointer | |
| P92 Reverse Linked List II | |
| P25 Reverse Nodes in k-Group✨✨✨ | |
| P19 Remove Nth Node From End of List | |
| P82 Remove Duplicates from Sorted List II✨✨✨ | |
| P61 Rotate List | |
| P86 Partition List | |
| P146 LRU Cache✨✨✨ | |
| P148 Sort List | |
| P160 Intersection of Two Linked Lists | |
| P206 Reverse Linked List✨✨✨ | |
| P234 Palindrome Linked List✨✨✨ | |
| P142 Linked List Cycle II✨✨✨ | |
| P24 Swap Nodes in Pairs |
Tree
Binary Tree Traversal
Preorder (Depth-First), Inorder, Postorder, Level Order, Morris Traversal
| Problem | Link |
|---|---|
| P104 Maximum Depth of Binary Tree | |
| P100 Same Tree | |
| P226 Invert Binary Tree | |
| P101 Symmetric Tree | |
| P105 Construct Binary Tree from Preorder and Inorder Traversal✨✨✨ | |
| P106 Construct Binary Tree from Inorder and Postorder Traversal✨✨✨ | |
| P117 Populating Next Right Pointers in Each Node II | |
| P114 Flatten Binary Tree to Linked List✨✨✨ | |
| P112 Path Sum | |
| P129 Sum Root to Leaf Numbers | |
| P124 Binary Tree Maximum Path Sum✨✨✨ | |
| P173 Binary Search Tree Iterator | |
| P222 Count Complete Tree Nodes✨✨✨ | |
| P236 Lowest Common Ancestor of a Binary Tree✨✨✨ | |
| P199 Binary Tree Right Side View | |
| P637 Average of Levels in Binary Tree | |
| P102 Binary Tree Level Order Traversal | |
| P103 Binary Tree Zigzag Level Order Traversal | |
| P530 Minimum Absolute Difference in BST | |
| P98 Validate Binary Search Tree | |
| P230 Kth Smallest Element in a BST | |
| P94 Binary Tree Inorder Traversal | |
| P543 Diameter of Binary Tree✨✨✨ | |
| P437 Path Sum III✨✨✨ |
Trie
A string as a node
1 | struct TrieNode { |
A char as a node
1 | struct TrieNode{ |
| Problem | Link |
|---|---|
| P14 Longest Common Prefix | |
| P208 Implement Trie (Prefix Tree) | |
| P211 Add and Search Word - Data Structure Design | |
| P212 Word Search II✨✨✨ | |
| P139 Word Break✨✨✨ |
Graph
DFS and BFS, Topological Sort
| Problem | Link |
|---|---|
| P200 Number of Islands✨✨✨ | |
| P130 Surrounded Regions | |
| P133 Clone Graph | |
| P399 Evaluate Division | |
| P207 Course Schedule✨✨✨ | |
| P210 Course Schedule II✨✨✨ | |
| P909 Snakes and Ladders✨✨✨ | |
| P443 Minimum Genetic Mutation | |
| P127 Word Ladder✨✨✨ | |
| P994 Rotting Oranges✨✨✨ |
Stack
| Title | Link |
|---|---|
| P20 Valid Parentheses | |
| P71 Simplify Path | |
| P155 Min Stack✨✨✨ | |
| P150 Evaluate Reverse Polish Notation✨✨✨ | |
| P224 Basic Calculator✨✨✨ | |
| P394 Decode String✨✨✨ | |
| P2197 Replace Non-Coprime Numbers in Array✨✨✨ | |
| P32 Longest Valid Parentheses ✨✨✨ |
Monotonic Stack
Core Rule of Monotonic StackThat is:When pushing an element onto the stack, if it breaks monotonicity, pop the top until monotonicity is restored。
Suppose we want to maintain a ‘monotonically decreasing stack’ (smallest at top)Either push, or pop several times and then push, always maintaining ‘monotonically decreasing’.
| Type | From bottom to top of stack | Function |
|---|---|---|
| Monotonically Increasing Stack | Values increasing | Suitable for finding the ‘next greater element’ |
| Monotonically decreasing stack | Values become smaller and smaller | Suitable for finding the ‘next smaller element’ |
Its core idea is:
Use monotonicity to filter out useless elements, ensuring the ‘most recent valid element’ is at the top of the stack
| Problem | Link |
|---|---|
| P3542 Minimum number of operations to make all elements zero ✨✨✨ | |
| P739 Daily Temperatures ✨✨✨ | |
| P84 Largest Rectangle in Histogram ✨✨✨ |
Queue
Monotonic Queue
| Problem | Link |
|---|---|
| P239 Sliding Window Maximum |
Matrix
| Problem | Link |
|---|---|
| P73 Set Matrix Zeroes ✨✨✨ | |
| P54 Spiral Matrix | |
| P48 Rotate Image ✨✨✨ | |
| P240 Search a 2D Matrix II✨✨✨ | |
| P36 Valid Sudoku | |
| P289 Game of Life✨✨✨ |
Difference and Prefix Sum

| Problem | Link |
|---|---|
| P2536 Increment Submatrix Elements by One✨✨✨ |
Sliding Window
Classic Template
1 | int left=0, right=0; |
| Problem | Link |
|---|---|
| P3 Longest Substring Without Repeating Characters | |
| P438 Find All Anagrams in a String | |
| P209 Minimum Size Subarray Sum | |
| P30 Substring with Concatenation of All Words ✨✨✨ | |
| P76 Minimum Window Substring ✨✨✨ | |
| P3186 Maximum Total Damage from Spell Casting |
Backtracking
Solving a backtracking problem is essentially a traversal process of a decision tree.

You only need to think about one question:
- Path: that is, the choices already made.
- Choice list: that is, the choices you can currently make.
- End condition: that is, the condition of reaching the bottom of the decision tree where no further choices can be made.
Classic template framework
1 | result = [] |
| Problem | Link |
|---|---|
| P46 Permutations | |
| P78 Subsets | |
| P17 Letter Combinations of a Phone Number | |
| P39 Combination Sum | |
| P22 Generate Parentheses✨✨✨ | |
| P79 Word Search | |
| P212 Word Search II | |
| P51 N-Queens✨✨✨ | |
| P52 N-Queens II | |
| P77 Combinations | |
| P131 Palindrome Partitioning ✨✨✨ |
Dynamic Programming
| Title | Link |
|---|---|
| P120 Triangle Minimum Path Sum | |
| P1039 Minimum Score Triangulation of Polygon | |
| P122 Best Time to Buy and Sell Stock II | |
| P55 Jump Game | |
| P45 Jump Game II | |
| P3147 Maximum Energy Drawn from a Wizard | |
| P3186 Maximum Total Damage from Casting Spells | |
| P3539 Sum of Array Products of Magic Sequences | |
| P392 Is Subsequence | |
| P474 Ones and Zeroes | |
| P70 Climbing Stairs | |
| P53 Maximum Subarray Sum | |
| Maximum Sum Circular Subarray | |
| House Robber | |
| Coin Change | |
| Longest Increasing Subsequence | |
| Word Break | |
| Minimum Path Sum | |
| Unique Paths II | |
| Longest Palindromic Substring | |
| P221 Maximal Square | |
| P72 Edit Distance | |
| P97 Interleaving String | |
| P123 Best Time to Buy and Sell Stock III | |
| P188 Best Time to Buy and Sell Stock IV | |
| P131 Palindrome Partitioning | |
| P118 Pascal’s Triangle | |
| P279 Perfect Squares | |
| P152 Maximum Product Subarray | |
| P416 Partition Equal Subset Sum | |
| P32 Longest Valid Parentheses | |
| P62 Unique Paths | |
| P1143 Longest Common Subsequence |
Greedy
| Problem | Link |
|---|---|
| P55 Jump Game✨✨✨ | |
| P45 Jump Game II✨✨✨ | |
| P134 Gas Station✨✨✨ | |
| P135 Candy✨✨✨ | |
| P1578 Minimum Time to Make Rope Colorful | |
| P3228 Maximum Number of Operations to Move Ones to the End | |
| P763 Partition Labels | |
| P121 Best Time to Buy and Sell Stock | |
| P976 Largest Perimeter Triangle |
Sorting
Merge Sort, Counting Sort, Quick Sort, Heap Sort
| Title | Link |
|---|---|
| P148 Sort List | |
| P2785 Sort Vowels in a String | |
| P3541 Find the Highest Frequency of Vowels and Consonants | |
| P274 H-Index | |
| P3005 Count Elements with Maximum Frequency |
Quick Sort
Lomuto partition
Each partition determines the position of one value.
1 |
|
Hoare partition
It does not require pivot to end up in the correct position, but guarantees:
1 |
|
This can also be written (recommended approach)
1 | // Quick sort function (Hoare partition scheme implementation) |
Reference Problems
| Problem | Link |
|---|---|
| P215 Kth Largest Element in an Array |
Heap Sort
ForComplete Binary TreeNumbering the nodes, the following relationship holds
| Item | 1-based Indexing(root = 1) | 0-based Indexing(root=0) |
|---|---|---|
| left child | ||
| right child | ||
| parent node | ||
| condition for having at least a left child | ||
| condition for existence of right child | ||
| leaf node condition | or | |
| condition for having only left child | and | |
| depth (root level=1) | ||
| depth (root level=0) |
1 |
|
| Title | Link |
|---|---|
| P3408 Design Task Manager | |
| P407 Trapping Rain Water II✨✨✨ | |
| P215 Kth Largest Element in an Array | |
| P373 Find K Pairs with Smallest Sums | |
| P295 Find Median from Data Stream✨✨✨ | |
| P239 Sliding Window Maximum | |
| P347 Top K Frequent Elements | |
| P502 IPO |
Divide and Conquer
The essence of binary search is:Finding the position of the first element in a sequence that satisfies a certain condition。
What often confuses people in binary search is: when to use less than or equal to in the while loop, and when not to use the equal sign;
First consider elements sorted in ascending order (descending is equivalent), which should be divided into two cases:
- No duplicate elements;
The problem in this case is generally: find whether a target element appears in the sequence, if it does, return its index; if not, return the position where it should be inserted.
That is, determine an interval [x, x], where target is the element at position x; if this element does not exist, the determined interval is [x+1, x], with the left boundary greater than the right boundary, meaning no element exists in the interval.
1 |
|
- With duplicate elements. The latter is a generalization of the former, meaning the algorithm for the latter also applies to the former.
The problem in this case is to determine the index of the first element greater than or equal to target, and the index of the first element greater than target, two subproblems.
(1) Find the lower bound (the index of the first element greater than or equal to target, which is x in [x, y))
1 | int LowerBound(const std::vector<int>& a, int target) |
(2) Find the upper bound (the index of the first element greater than target, which is y in [x, y))
1 | int UpperBound(const std::vector<int>& a, int target) |
Take the following problem as an example:
1 |
|
When finding the end, use the upper mid:mid = left + (right - left + 1) / 2;This ensures mid > left, so the interval definitely shrinks.
| Problem | Link |
|---|---|
| P34 Find First and Last Position of Element in Sorted Array✨✨✨ | |
| P108 Convert Sorted Array to Binary Search Tree | |
| P148 Sort List | |
| P427 Construct Quad Tree | |
| P23 Merge k Sorted Lists | |
| P35 Search Insert Position | |
| P74 Search a 2D Matrix | |
| P240 Search a 2D Matrix II✨✨✨ | |
| P162 Find Peak Element | |
| P33 Search in Rotated Sorted Array | |
| P153 Find Minimum in Rotated Sorted Array | |
| P4 Median of Two Sorted Arrays |
Union-Find
| Problem | Link |
|---|---|
| P3607 Grid Maintenance |

