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.
Operation | Frequency |
---|---|
Variable Declaration | |
Assignment Statement | |
Less than Compare | |
Equal to Compare | |
Array Access | |
Increment | to |
Key Notes:
- Estimate running time (or memory) as a function of input size
- Ignore lower order terms
- When is large, terms are negligible.
- When is small, we don’t care.
1.2 Order-of-Growth Classifications
1.2.1 Common Classifications
Order of Growth | Name | Typical Code Framework | Description | Example | |
Constant |
| Statement | Add two numbers | ||
Logarithmic |
| Divide in half | Binary search | ||
Linear |
| Loop | Find the maximum | ||
Linearithmatic | See mergesort lecture | Divide and conquer | Mergesort | ||
Quadratic |
| Double loop | Check all pairs | ||
Cubic |
| Triple loop | Check all triples | ||
Exponential | See combinatorial search lecture | Exhaustive search | Check all subsets |
1.2.2 Binary Search
Procedure: Compare key against middle entry
- Too small, go left.
- Too big, go right.
- Equal, found!
Property: Binary search uses to search in a sorted array of size .
Proof:
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;}
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;}
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
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
- Sort (distinct) numbers =>
- Binary Search for each pair =>
Better algorithm: Sorting & Two pointers =>
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; }}
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;}
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