Algorithm

Table of Contents

1. Data Structure

1.1. Array

  • Occupy fixed contiguous memory space.

1.1.1. Time Complexity

  • Insertion, Deletion: O(N)
  • Index Access: O(1)
  • Search: O(N)

1.2. Dynamic Array

  • Vector
  • An array that changes its length accordingly.

1.3. Linked List

1.3.1. Singly Linked List

  • Node: Data + Pointer to the next node. Last node has null pointer.
1.3.1.1. Time Complexity
  • Insertion, Deletion: O(1)
  • Search: O(N)

1.3.2. Doubly Linked List

  • Node: Data + Pointer to the previous node + Pointer to the next node.
  • Same time complexity with the singly linked list but it can traverse backward.

1.3.3. Circular Linked List

  • The tail points to the head and vice versa. So no need to keep track of the tail.

1.3.4. Iterator

  • It keeps track of the index of the current node by traversing the nodes one at a time.
  • Python list is most likely a circular linked list. One can perform del on it, and mention the last element with a[-1].

1.4. Stack

  • Last In First Out, LIFO.

1.5. Queue

  • Fist In Fist Out, FIFO.

1.6. Deque

  • Combination of stack and queue. Data can be pushed and poped from both side, with no ordering.

1.7. Hash Table

  • Use a hash function, not necessarily a cryptographic hash function, to determine the index of an element. The data at each index is a linked list, so that the hash collision can be mitigated.

1.7.1. Hash Collision

  • When two hash points to the same index, then we append both in the list of corresponding index.
  • Then, if we need to search for it, we preform a sequential search on that list.
  • Normally the index space is set to be three to four times larger than the number of indexes needed.
  • Enables \(O(1)\) insertion/deletion/search.

1.8. Tree

1.8.1. Binary Tree

Tree where every node has two childs: left and right. The left is always smaller than the parent, and right is always greater than parent.

1.8.2. B-Tree

  • It's like an extended binary tree.

Set amount of maximum number of key in each node, and the intervals between keys are also checked.

1.8.2.1. Addition
leaf = b_tree.find_leaf(key)
if leaf.not_full:
  leaf.add(key)
  return
leaf.split(key) # split the node into equal sized child nodes, and append the middle key to the parent
                # do it recursively, up to the root node
1.8.2.2. Deletion
  • Borrow if available
  • Merge if available

1.8.3. B+ Tree

  • Only the leafs are used to store keys.

1.8.4. (Page) B-Tree

  • Each node can contain fixed amount of data, instead of fixed amount of keys.
  • Apparently SQLite uses it.

2. Search

2.1. Binary Search

  • Time Complexity: \(O(\log N)\)
  • Require sorted array

Algorithm

  1. left = 0 and right = len(array).
  2. Compare the element at mid = (left + right)/2 with the desired value.
  3. If it is the element then return the mid otherwise depending on whether it is larger than or smaller than the value change the right or left to after or before the mid.

2.2. Breadth First Search

Algorithm

marked = [False] * G.size()
def bfs(G, v): # G is a graph and v is an integer representing a vertex
  queue = [v]
  while len(queue) > 0:
    v = queue.pop(0)
    if not marked[v]:
      visit(v)
      marked[v] = True
      for w in G.neighbor(v):
        if not marked[w]:
          queue.append(w)

Applications

  • Shortest Path Problem
  • Flood Fill Problem
    • Find densely-connected Component

2.3. Depth First Search

  • DFS
  • 'Visiting' all or parts of a graph in depth first way.

2.3.1. Graph Traversal

  • 'Visiting' all the vertices in a graph.
2.3.1.1. Preorder and Postorder

Preorder traversal visits the vertex when it first visit it, on the other hand postorder traversal visits the vertex when every option is exhausted except retreating.

2.3.2. Implementation

2.3.2.1. Recursive
marked = [False] * G.size()
def dfs(G, v): # G a graph and v is an integer
  visit(v)
  marked[v] = True
  for w in G.neighbors(v):
    if not marked[w]:
      dfs(G, w)

The marking becomes irrelevant when \(G\) is a tree, since the leafiness is the mark.

The validation step for the pdf2xls is postorder depth first search on directed tree.

2.3.2.2. Iterative
marked = [False] * G.size()
def dfs(G, v): # G is a graph v is an integer
  stack = [v]
  while len(stack) > 0:
    v = stack.pop()
    if not marked[v]:
      visit[v]
      marked[v] = True
      for w in G.neighbors(v):
        if not marked[w]:
          stack.append(w)

The information in time, in a for loop, gets stored in the memory, stack.

While more wordful, this approach is more extensible.

2.3.3. Application

  • Cycle Detection
  • Find Connected Components
  • Reverse of the result from postorder DFS is a topological sort in a directed acyclic graph, which is an ordering based on the topology of a graph.
    • This is because the exhaustion of options is equivalent to checking that it's larger than all its neighbors.
  • Maze Generation
    • Include squares based on DFS

2.4. Boyer-Moore String-Search Algorithm

  • Used in grep

Algorithm for searching for a short pattern in a long text.

3. Sort

3.1. Bubble Sort

  • Change with the next one if out of order.
  • Time Complexity: \( O(N^2) \)
  • Good for mostly sorted array.

3.2. Selection Sort

  • Find the smallest element within the undetermined next part and let it be the first one within the part.
  • Time Complexity: \(O(N^2)\)
  • Consistently slow.

3.3. Insertion Sort

  • Insert the next element into the correct position within the sorted previous part.
  • Time Complexity: \(O(N^{2})\)
  • Usually fast, but slow when the array is in reverse order, to the exact point of the selection sort.
  • Exceptional when few elements added to a sorted array.

3.4. Radix Sort

  • Sort the array digit by digit from the least significant digit.
  • Uses an array of array that stores the elements in an outer array that matches its digit and append it in the end of the inner array, later to be read from the start.
  • Time Complexity: \(O(kN)\) where \(k\) is the largest number of digits.
  • Not in-place

3.5. Merge Sort

  • Recursively perform merge sort on half of the input and merge those two halves.
  • Time Complexity: \(O(N\log N)\)
  • Not in-place Sort, in which the elements are temporarily stored outside of the array.

3.6. Quick Sort

  • Determine a pivot (the last element, in this case) and gather the largers and the smallers, and then perform quick sort on those recursively.
  • During the pivoting stage, two pointer are used one-pointer 1-for the end of the smallers, and the other-pointer 2-for the next element to swap position.
  • March the pointer 2 until it finds an element smaller than the pivot and swap it with the next element of the pointer 1, march the pointer 1 by 1, again start marching the pointer 2 until it reaches the end (in this case, the pivot).
    • When set the last element to be the pivot the pivot swapped with the first larger element as the last step.
  • Time Complexity: \(O(N\log N)\) on average, \(O(N^2)\) in the worst case, but use of some technique prevents the worst case scenario.
    • Pivot can be chosen to be the leftmost element or middle element, in simple implementation.
    • The most common method that eliminates the problem is to use the median of the first, last, middle elements.
  • Not stable, the order of same valued element is not preserved.

3.7. Heap Sort

  • Find the largest element within the undetermined previous part and let it be the last one within the part.
  • But unlike the selection sort it uses heap, a binary tree in which each node has two or less child nodes, to find the maximum element.
    • The binary tree can be encoded in an array, in this case, the original array is the heap.
      • Set the root node to be at the index 1. Child nodes have the index of 2i and 2i + 1 of the parent index i.
    • First one need to make the heap into a max-heap, in which all the nodes are larger than or equal to all of their childs.
      • Starting from the nodes that has the depth of just 1 smaller than the leaf nodes, find the largest node among the node and its two children, and swaps with the child node if it's larger. Repeat this until we reach the root node.
      • Note that after a node have swapped, the change needs to be propagated to the children of the swapped child node.
    • After max-heap has been achieved than the first element is the largest one, so swaps it with the last element of the unsorted part, and make max-heap again without the just determined element.
      • This reconstruction of max-heap is simple because it only moves one element at each depth.
  • Time Complexity: \(O(N\log N)\)
  • Not stable

4. Select

4.1. Quickselect

  • Hoare's Selection Algorithm

Find the \( k \)th smallest element in a list.

5. Count

5.1. Hyperloglog

Probablistically count the number of distinct elements.

Hash each element and find the maximum runs of zeros. If run is longer than there are more distinct elements.

  1. Start with a set of elements and few score variables that store the length of longest run.
  2. Calculate hash of an element
  3. Select one of the scores, and store the length of run of zeros if it is larger than the score.
  4. Repeat until exhausted
  5. Take the harmonic mean of the scores
  6. Larger the mean, larger the number of distinct elements.

We can run this algorithm in parallel, and select the larger score (at each position of score vector).

6. Greedy Algorithm

Repeatedly find the best option locally and get the approximation of the global best.

7. Dynamic Programming

It is recursion with memoization(??, ????)

"Correctness of bruteforcing and efficiency of greedy algorithm."

Old implementation of diff algorithm is one of them.(Tech With Nikola, ????) It is about finding the longest common subsequence.

8. Dijkstra's Algorithm

8.1. A* Algorithm

9. Spell Checker

It uses dictionary to spot typos and calculates the edit distance to suggest the corrections.

9.1. spell

UNIX spell checker that showed recommendations for typos.

9.2. Levenshtein Distance Algorithm

Devised by Soviet scientist, Vladimir Levenshtein in 1965.

def lev(a: str, b: str) -> int:
    if len(a) == 0:
        return len(b)
    if len(b) == 0:
        return len(a)
    if head(a) == head(b): # head(a) = a[0]
        return lev(tail(a), tail(b)) # tail(a) = a[1:]
    return 1 + min(
        lev(tail(a), b),      # case of insertion
        lev(a, tail(b)),      # case of deletion
        lev(tail(a), tail(b)) # case of substitution
    )

9.3. Wagner

  • Robert Wagner and Micheal Fischer
  • Used dynamic programming upon the Levenshtein distance algorithm.

10. Minimax Approximation

Process or the result of finding a polynomial \( p^*(x) \) such that the infinity norm \( \Vert f(x)-p^*(x)\Vert_\infty=\max_{\xi\in[a,b]}|f(\xi)-p^*(\xi)|\) is minimum.

10.1. One-Point Exchange Method

Given \(n\) points on the domain, it is possible to find degree \(n-2\) polynomial \(p(x)\), such that at every given points \(f(x_i)-p(x_i)\) is distinct, sign alternating, with same error \(h\), using matrix equation,

\begin{bmatrix} 1&\xi_1&\xi_1^2&1\\ 1&\xi_2&\xi_2^2&-1\\ 1&\xi_3&\xi_3^2&1\\ 1&\xi_4&\xi_4^2&-1 \end{bmatrix} \begin{bmatrix} a\\ b\\ c\\ h \end{bmatrix} = \begin{bmatrix} f(\xi_1)\\ f(\xi_2)\\ f(\xi_3)\\ f(\xi_4) \end{bmatrix}
  1. We find the point with the largest error, and substitute it to the closest point with the same sign of error.
  2. Repeat this multiple times and we get the minimax approximation.

10.2. Remez Algorithm

Produce the minimax approximation of a function in an iterative way.

  1. One-point exchange method, but exchange all the points for the points where the errors are at the local maxima.
  2. Repeat this until every points of extremum errors is equal-magnitude and sign-alternating.

11. Linear Programming

  • A linear program is comprises of
    • set of variables
    • set of linear inequalities
    • a linear function, called objective function because it is what we want to maximize.

11.1. Simplex method

  1. Introduce slack variables for every inequality. Initially the slack variables are basic (loose), and the variables are non-basic (tight).
  2. Find a variable to loosen. One of the rules to find it is the Dantzig's pivot rule, which takes a variable with largest non-negative coefficient in the object function.
  3. Find a basic variable with largest non-positive constant over coefficient ratio, and tighten it.
  4. Rewrite the equations for the basic variables.
  5. Repeat step 2 through 4, until every variable in the object function has non-positive coefficient.
  6. Set the slack variables to zero, to obtain the maximum.

11.1.1. Example

The problem statement:

\begin{align*} x_1, x_2 &\ge 0 \\ x_1 &\le 3 \\ x_2 &\le 4 \\ x_1+x_2 &\le 5 \\[5px] \text{obj.}\ 1.2x_1 &+ 1.7x_2. \end{align*}
  1. Introduce slack variables \(s_1,s_2,s_3 \ge 0\). Roman letters indicates it is tight.

    \begin{align*} s_1 &= 3 - \mathrm{x}_1\\ s_2 &= 4 - \mathrm{x}_2\\ s_3 &= 5 - \mathrm{x}_1 - \mathrm{x}_2\\[5px] \text{obj.}\ &1.2\mathrm{x}_1 + 1.7\mathrm{x}_2 \nonumber \end{align*}
  2. Loosen the appropriate variable: \(x_2\) with coefficient \(1.7\).

    \begin{align*} s_1 &= 3 - \mathrm{x}_1\\ s_2 &= 4 - x_2\\ s_3 &= 5 - \mathrm{x}_1 - x_2\\[5px] \text{obj.}\ &1.2\mathrm{x}_1 + 1.7x_2 \end{align*}
  3. Tighten the appropriate variable: \(s_2\) with \(4\) (constant in the equation) over \(-1\) (coefficient of \(x_2\)).

    \begin{align*} s_1 &= 3 - \mathrm{x}_1\\ \mathrm{s}_2 &= 4 - x_2\\ s_3 &= 5 - \mathrm{x}_1 - x_2\\[5px] \text{obj.}\ &1.2\mathrm{x}_1 + 1.7x_2 \end{align*}
  4. rewrite the equations.

    \begin{align*} s_1 &= 3 - \mathrm{x}_1\\ x_2 &= 4 - \mathrm{s}_2\\ s_3 &= 1 - \mathrm{x}_1 + \mathrm{s}_2\\[5px] \text{obj.}\ &1.2\mathrm{x}_1 - 1.7\mathrm{s}_2 + 6.8 \end{align*}
  5. repeat.

    \begin{align*} s_1 &= 3 - x_1\\ x_2 &= 4 - \mathrm{s}_2\\ s_3 &= 1 - x_1 + \mathrm{s}_2\\[5px] \text{obj.}\ &1.2x_1 - 1.7\mathrm{s}_2 + 6.8, \end{align*} \begin{align*} s_1 &= 3 - x_1\\ x_2 &= 4 - \mathrm{s}_2\\ \mathrm{s}_3 &= 1 - x_1 + \mathrm{s}_2\\[5px], \end{align*} \begin{align*} s_1 &= 2 + \mathrm{s}_3 - \mathrm{s}_2\\ x_2 &= 4 - \mathrm{s}_2\\ x_1 &= 1 - \mathrm{s}_3 + \mathrm{s}_2\\[5px] \text{obj.}\ &-1.2\mathrm{s}_3 - 0.5\mathrm{s}_2 + 8, \end{align*}
  6. Now all coefficients are negative we can safely say \(s_2 = s_3 = 0\) and \(\max(\text{obj.)} = 8\).

11.2. Dual Linear Program

From a linear program, we can induce dual linear program by expressing the bound of the object function in terms of scalar \(y_i\) multiple of linear inequalities, while flipping the objective of the problem, maximum to minimum and vice versa.

\begin{align*} x_1, x_2 &\ge 0 \\ x_1 &\le 3 \\ x_2 &\le 4 \\ x_1+x_2 &\le 5 \\[5px] \text{obj.}\ \max\ 1.2x_1 &+ 1.7x_2 \end{align*}

corresponds to

\begin{align*} y_1, y_2, y_3 &\ge 0 \\ y_1+y_3 &\ge 1.2 \\ y_2+y_3 &\ge 1.7 \\[5px] \text{obj.}\ \min\ 3y_1 &+ 4y_2+5y_3. \end{align*}

11.2.1. Duality theorem

It states that a dual proves that the other is optimal.

11.3. Integer linear programming

It is solving a linear program with integer variables.

12. Number Theory

13. Randomized Numerical Linear Algebra

  • Rand-NLA

Given a matrix \( \mathbf{A} \) and a vector \( \mathbf{b} \), we choose a selection matrix \( \mathbf{S} \) that reduces the dimension, and find the solution to the least squares problem:

\begin{align*} \mathbf{x}^{*} &:= \mathop{\rm arg\ min}_{\mathbf{x}} \Vert {\bf Ax - b} \Vert_2 \\ \tilde{\mathbf{x}} &:= \mathop{\rm arg\ min}_{\mathbf{x}} \Vert {\bf SAx - Sb} \Vert_2. \end{align*}

With clever choice of \( \mathbf{S} \) we have \[ \Vert \mathbf{A}\tilde{\mathbf{x}} - \mathbf{b} \Vert_2 \approx \Vert \mathbf{A}\mathbf{x}^{*} - \mathbf{b} \Vert_2. \]

14. Fast Fourier Transform

  • FFT

Perform discrete Fourier transform efficiently.

\(f(t_n)\to \hat{f}(\omega_n), n\in [0, N-1]\) where

  • \(\omega_0\) is the DC offset
  • \(\omega_{n< \text{Nyquist}}\) is the \(n\) cycles per field of view
  • \(\omega_{n>\text{Nyquist}}\) is the \(-(N-n)\) cycles per field of view.

Divide into an even part and an odd part and evaluate: \[ \begin{bmatrix}z_0\\z_1\\z_2\\z_3\end{bmatrix}=\begin{bmatrix}1&1&1&1\\1&i&-1&-i\\1&-1&1&-1\\1&-i&-1&i\end{bmatrix}\begin{bmatrix}x_0\\x_1\\x_2\\x_3\end{bmatrix}\rightsquigarrow{\begin{bmatrix}1&1\\1&-1\end{bmatrix}\begin{bmatrix}x_0\\x_2\end{bmatrix} + \begin{bmatrix}1&0\\0&i\end{bmatrix}\begin{bmatrix}1&1\\1&-1\end{bmatrix}\begin{bmatrix}x_1\\x_3\end{bmatrix}\atop \begin{bmatrix}1&1\\1&-1\end{bmatrix}\begin{bmatrix}x_0\\x_2\end{bmatrix} - \begin{bmatrix}1&0\\0&i\end{bmatrix}\begin{bmatrix}1&1\\1&-1\end{bmatrix}\begin{bmatrix}x_1\\x_3\end{bmatrix}} \]

14.1. Implementation

def fft(x):
  # x = [x_0, x_1, ..., x_{N-1}]
  n = len(x) # n = 2^k
  if n == 1:
    return x

  ω = e**{i*2*pi/n}

  x_even, x_odd = x[::2], x[1::2]
  z_even, z_odd = fft(x_even), fft(x_odd)

  z = [0]*n
  for j in range(n/2):
    z[j] = z_even[j] + ω**j*z_odd[j]
    z[j+n/2] = z_even[j] - ω**j*z_odd[j]

  return z

15. Gilbert-Johnson-Keerthi Algorithm

  • GJK Algorithm

Detect whether two shapes intersect.

16. Expanding Polytope Algorithm

It calculates the depth and the normal vector of collision.

17. Maze Generating Algorithm

17.1. Depth First Search

17.2. Prim's Algorithm

17.3. Kruskal's Algorithm

17.4. Origin Shift Algorithm (CaptainLuma)

18. Reed-Solomon Error Correction

  • Reed-Solomon Codes(RS Codes)

Used in CDs, DVDs, Blu-ray discs, QR coded, data transmission technologies.

Send one or two additional points that is on the Lagrange interpolation of the other points.

19. Reference

Author: Jeemin Kim

Created: 2026-08-09 Sun 07:11