Data Structures and Algorithms

Last Modified: 2/12/2025

1 Data Structures and Algorithms Overview

1.1 Mathematical Models

Cost Models: Use some basic operations as a proxy for running time.

OperationFrequency
Variable DeclarationN+2N + 2
Assignment StatementN+2N + 2
Less than Compare(N+1)(N+2)2\frac{\left(N + 1\right)\left(N + 2\right)}{2}
Equal to CompareN(N1)2\frac{N\left(N - 1\right)}{2}
Array AccessN(N1)N\left(N - 1\right)
IncrementN(N1)2\frac{N\left(N - 1\right)}{2} to N(N1)N\left(N - 1\right)

Key Notes:

1.2 Order-of-Growth Classifications

1.2.1 Common Classifications

Order of GrowthNameTypical Code FrameworkDescriptionExampleT(2N)/T(N)T\left(2N\right)/T\left(N\right)
11Constant
a = b + c;
StatementAdd two numbers11
logN\log NLogarithmic
while (N > 1) N /= 2;
Divide in halfBinary search1-1
NNLinear
for (int i = 0; i < N; i++)
{...}
LoopFind the maximum22
NlogNN \log NLinearithmaticSee mergesort lectureDivide and conquerMergesort2-2
N2N^2Quadratic
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
{...}
Double loopCheck all pairs44
N3N^3Cubic
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
for (int k = 0; k < N; k++)
{...}
Triple loopCheck all triples88
2N2^NExponentialSee combinatorial search lectureExhaustive searchCheck all subsetsT(N)T\left(N\right)

Procedure: Compare key against middle entry

Property: Binary search uses 1+logN1 + \log N to search in a sorted array of size NN.

Proof:

T(N)=number of compares to binary search in a sorted array of sizeN T(N) = \text{number of compares to binary search in a sorted array of size} \leq N T(N)T(N2)+1T(N4)+1+1T(N8)+1+1+1T(NN)+1+1+1++11+logN\begin{align*} T\left(N\right) &\leq T\left(\frac{N}{2}\right) + 1 \\ &\leq T\left(\frac{N}{4}\right) + 1 + 1\\ &\leq T\left(\frac{N}{8}\right) + 1 + 1 + 1 \\ &\vdots \\ &\leq T\left(\frac{N}{N}\right) + 1 + 1 + 1 + \cdots + 1 \\ &\leq 1 + \log N \end{align*}
BinarySearch.java
15 collapsed lines
public static int binarySearch(int[] a, int key) {
int lo = 0;
int hi = a.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (key < a[mid]) {
hi = mid - 1;
} else if (key > a[mid]) {
lo = mid + 1;
} else {
return mid;
}
}
return -1;
}
BinarySearch.cpp
17 collapsed lines
#include <vector>
int binarySearch(std::vector<int> arr, int x) {
int l = 0, r = arr.size() - 1;
while (l <= r) {
int m = l + (r - l) / 2;
if (arr[m] == x) {
return m;
}
if (arr[m] < x) {
l = m + 1;
} else {
r = m - 1;
}
}
return -1;
}
BinarySearch.py
11 collapsed lines
def binary_search(arr, x):
l, r = 0, len(arr) - 1
while l <= r:
m = l + (r - l) // 2
if arr[m] == x:
return m
if arr[m] < x:
l = m + 1
else:
r = m - 1
return -1

1.2.3 3-Sum

LeetCode 15: 3Sum

Description: Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k , and nums[i] + nums[j] + nums[k] == 0.

Procedure

  1. Sort NN (distinct) numbers => O(NlogN)O\left(N \log N\right)
  2. Binary Search for each pair (ai+aj)-\left(a_i + a_j\right) => O(N2logN)O(N^2 \log N)

Better algorithm: Sorting & Two pointers => O(N2)O\left(N^2\right)

3Sum.java
46 collapsed lines
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public Solution() {
}
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> answers = new ArrayList<>();
for (int first = 0; first < n; ++first) {
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
int third = n - 1;
int target = -nums[first];
for (int second = first + 1; second < n; second++) {
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
while (second < third && nums[second] + nums[third] > target) {
--third;
}
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> list = new ArrayList<>();
list.add(nums[first]);
list.add(nums[second]);
list.add(nums[third]);
answers.add(list);
}
}
}
return answers;
}
}
3Sum.cpp
37 collapsed lines
#include <vector>
#include <algorithm>
std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {
const int n = static_cast<int>(nums.size());
std::sort(nums.begin(), nums.end());
std::vector<std::vector<int>> answer;
for (int first = 0; first < n; first++) {
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
int third = n - 1;
const int target = -nums[first];
for (int second = first + 1; second < n; second++) {
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
while (second < third && nums[second] + nums[third] > target) {
--third;
}
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
answer.emplace_back(std::vector<int>{nums[first], nums[second], nums[third]});
}
}
}
return answer;
}
3Sum.py
28 collapsed lines
from typing import List
def threeSum(nums: List[int]) -> List[List[int]]:
n = len(nums)
nums.sort()
ans = list()
for first in range(n):
if first > 0 and nums[first] == nums[first - 1]:
continue
third = n - 1
target = -nums[first]
for second in range(first + 1, n):
if second > first + 1 and nums[second] == nums[second - 1]:
continue
while second < third and nums[second] + nums[third] > target:
third -= 1
if second == third:
break
if nums[second] + nums[third] == target:
ans.append([nums[first], nums[second], nums[third]])
return ans