跳转至

C++ 算法模板库

竞赛级算法模板 | 适用于 LeetCode 和算法竞赛

所有模板均包含详细注释、时间/空间复杂度分析


📋 目录

  1. 基础工具函数
  2. 排序算法
  3. 搜索算法
  4. 图论算法
  5. 动态规划
  6. 数据结构
  7. 回溯算法
  8. 数学算法

1. 基础工具函数

1.1 打印数组

C++
#include <bits/stdc++.h>
using namespace std;

/**
 * 打印一维数组
 * 时间: O(n)
 * 空间: O(1)
 */
template<typename T>
void printArray(const vector<T>& arr, const string& name = "") {
    if (!name.empty()) cout << name << ": ";
    cout << "[";
    for (int i = 0; i < arr.size(); i++) {
        if (i > 0) cout << ", ";
        cout << arr[i];
    }
    cout << "]" << endl;
}

使用示例:

C++
vector<int> arr = {1, 2, 3, 4, 5};
printArray(arr, "数组");  // 输出: 数组: [1, 2, 3, 4, 5]

1.2 打印二维数组

C++
/**
 * 打印二维数组
 * 时间: O(m×n)
 * 空间: O(1)
 */
template<typename T>
void print2DArray(const vector<vector<T>>& arr, const string& name = "") {
    if (!name.empty()) cout << name << ":" << endl;
    for (const auto& row : arr) {
        cout << "  [";
        for (int i = 0; i < row.size(); i++) {
            if (i > 0) cout << ", ";
            cout << row[i];
        }
        cout << "]" << endl;
    }
}

2. 排序算法

算法 平均时间 最坏时间 空间 稳定性
快速排序 O(n log n) O(n²) O(log n) 不稳定
归并排序 O(n log n) O(n log n) O(n) 稳定
堆排序 O(n log n) O(n log n) O(1) 不稳定

2.1 快速排序 - 原地版

C++
/**
 * 快速排序 - 原地版(Lomuto分区)
 * 时间: O(n log n) 平均,O(n²) 最坏
 * 空间: O(log n)
 */
void quickSort(vector<int>& arr, int low, int high) {
    if (low < high) {
        // 选择最后一个元素作为pivot
        int pivot = arr[high];
        int i = low - 1;

        // 分区操作
        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                swap(arr[i], arr[j]);
            }
        }
        swap(arr[i + 1], arr[high]);
        int pi = i + 1;

        // 递归排序
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

使用示例:

C++
vector<int> arr = {3, 6, 8, 10, 1, 2, 1};
quickSort(arr, 0, arr.size() - 1);
// 结果: [1, 1, 2, 3, 6, 8, 10]

2.2 快速排序 - 简洁版

C++
/**
 * 快速排序 - 简洁版(返回新数组)
 * 适合理解算法思想
 */
vector<int> quickSortSimple(vector<int> arr) {
    if (arr.size() <= 1) return arr;

    int pivot = arr[arr.size() / 2];
    vector<int> left, middle, right;

    for (int x : arr) {
        if (x < pivot) left.push_back(x);
        else if (x == pivot) middle.push_back(x);
        else right.push_back(x);
    }

    left = quickSortSimple(left);
    right = quickSortSimple(right);

    left.insert(left.end(), middle.begin(), middle.end());
    left.insert(left.end(), right.begin(), right.end());
    return left;
}

2.3 归并排序

C++
/**
 * 归并排序
 * 时间: O(n log n)
 * 空间: O(n)
 * 特点: 稳定排序
 */
void mergeSort(vector<int>& arr, int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;

        // 递归排序左右两部分
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);

        // 合并两个有序数组
        vector<int> temp(right - left + 1);
        int i = left, j = mid + 1, k = 0;

        while (i <= mid && j <= right) {
            if (arr[i] <= arr[j]) temp[k++] = arr[i++];
            else temp[k++] = arr[j++];
        }

        while (i <= mid) temp[k++] = arr[i++];
        while (j <= right) temp[k++] = arr[j++];

        // 复制回原数组
        for (int p = 0; p < k; p++) {
            arr[left + p] = temp[p];
        }
    }
}

2.4 堆排序

C++
/**
 * 堆排序
 * 时间: O(n log n)
 * 空间: O(1)
 */
void heapify(vector<int>& arr, int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && arr[left] > arr[largest]) largest = left;
    if (right < n && arr[right] > arr[largest]) largest = right;

    if (largest != i) {
        swap(arr[i], arr[largest]);
        heapify(arr, n, largest);
    }
}

void heapSort(vector<int>& arr) {
    int n = arr.size();

    // 建堆(从最后一个非叶子节点开始)
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(arr, n, i);
    }

    // 排序:将堆顶元素移到末尾,重新调整堆
    for (int i = n - 1; i > 0; i--) {
        swap(arr[0], arr[i]);
        heapify(arr, i, 0);
    }
}

3. 搜索算法

3.1 二分搜索 - 标准版

C++
/**
 * 二分搜索 - 标准版
 * 时间: O(log n)
 * 空间: O(1)
 * 返回: target的索引,不存在返回-1
 * 前提: 数组必须是有序的
 */
int binarySearch(const vector<int>& arr, int target) {
    int left = 0, right = arr.size() - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;  // 防止溢出

        if (arr[mid] == target) return mid;
        else if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }

    return -1;
}

使用示例:

C++
vector<int> arr = {1, 3, 5, 7, 9, 11, 13};
int idx = binarySearch(arr, 7);  // 返回: 3

3.2 Lower Bound

C++
/**
 * lower_bound - 第一个 >= target 的位置
 * 时间: O(log n)
 * 空间: O(1)
 * 返回: 插入位置(可能等于数组长度)
 */
int lowerBound(const vector<int>& arr, int target) {
    int left = 0, right = arr.size();

    while (left < right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] < target) left = mid + 1;
        else right = mid;
    }

    return left;
}

3.3 Upper Bound

C++
/**
 * upper_bound - 第一个 > target 的位置
 * 时间: O(log n)
 * 空间: O(1)
 */
int upperBound(const vector<int>& arr, int target) {
    int left = 0, right = arr.size();

    while (left < right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] <= target) left = mid + 1;
        else right = mid;
    }

    return left;
}

STL等效函数:

C++
// C++ STL中的二分搜索函数
#include <algorithm>

lower_bound(arr.begin(), arr.end(), target);  // 第一个 >= target
upper_bound(arr.begin(), arr.end(), target);  // 第一个 > target
binary_search(arr.begin(), arr.end(), target); // 是否存在


4. 图论算法

4.1 BFS - 广度优先搜索

C++
/**
 * BFS - 广度优先搜索
 * 时间: O(V + E)
 * 空间: O(V)
 * 适用: 无权图最短路径、层序遍历
 */
vector<int> bfs(const unordered_map<int, vector<int>>& graph, int start) {
    vector<int> result;
    unordered_set<int> visited;
    queue<int> q;

    visited.insert(start);
    q.push(start);

    while (!q.empty()) {
        int node = q.front(); q.pop();
        result.push_back(node);

        auto it = graph.find(node);
        if (it != graph.end()) {
            for (int neighbor : it->second) {
                if (visited.find(neighbor) == visited.end()) {
                    visited.insert(neighbor);
                    q.push(neighbor);
                }
            }
        }
    }

    return result;
}

使用示例:

C++
unordered_map<int, vector<int>> graph = {
    {0, {1, 2}},
    {1, {2}},
    {2, {0, 3}},
    {3, {3}}
};
vector<int> result = bfs(graph, 2);  // [2, 0, 3, 1]

4.2 DFS - 深度优先搜索

C++
/**
 * DFS - 深度优先搜索(递归版)
 * 时间: O(V + E)
 * 空间: O(V)
 */
void dfsRecursive(const unordered_map<int, vector<int>>& graph,
                  int node, unordered_set<int>& visited, vector<int>& result) {
    visited.insert(node);
    result.push_back(node);

    auto it = graph.find(node);
    if (it != graph.end()) {
        for (int neighbor : it->second) {
            if (visited.find(neighbor) == visited.end()) {
                dfsRecursive(graph, neighbor, visited, result);
            }
        }
    }
}

// 使用包装函数
vector<int> dfs(const unordered_map<int, vector<int>>& graph, int start) {
    vector<int> result;
    unordered_set<int> visited;
    dfsRecursive(graph, start, visited, result);
    return result;
}

4.3 Dijkstra最短路径算法

C++
/**
 * Dijkstra最短路径算法
 * 时间: O((V + E) log V)
 * 空间: O(V)
 * 适用: 非负权图的单源最短路径
 */
vector<int> dijkstra(const vector<vector<pair<int, int>>>& graph, int start) {
    int n = graph.size();
    vector<int> dist(n, INT_MAX);
    dist[start] = 0;

    // 小顶堆: {距离, 节点}
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push({0, start});

    while (!pq.empty()) {
        auto [d, u] = pq.top(); pq.pop();

        if (d > dist[u]) continue;  // 已处理过

        for (auto [v, w] : graph[u]) {
            if (dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                pq.push({dist[v], v});
            }
        }
    }

    return dist;
}

使用示例:

C++
// 邻接表: graph[u] = {{v, weight}, ...}
vector<vector<pair<int, int>>> graph = {
    {{1, 4}, {2, 1}},    // 节点0
    {{3, 1}},            // 节点1
    {{1, 2}, {3, 5}},    // 节点2
    {}                   // 节点3
};
vector<int> dist = dijkstra(graph, 0);
// dist = [0, 3, 1, 4]


5. 动态规划

5.1 爬楼梯

C++
/**
 * 爬楼梯 - 动态规划
 * 时间: O(n)
 * 空间: O(1)
 * 问题: 每次爬1或2阶,n阶有多少种方法
 * 状态转移: dp[i] = dp[i-1] + dp[i-2]
 */
int climbStairs(int n) {
    if (n <= 2) return n;

    int prev = 1, curr = 2;
    for (int i = 3; i <= n; i++) {
        int next = prev + curr;
        prev = curr;
        curr = next;
    }

    return curr;
}

5.2 0-1背包问题

C++
/**
 * 0-1背包问题
 * 时间: O(n × capacity)
 * 空间: O(capacity)
 * 问题: n个物品,重量weights[i],价值values[i],容量capacity,求最大价值
 */
int knapsack01(const vector<int>& weights, const vector<int>& values, int capacity) {
    int n = weights.size();
    vector<int> dp(capacity + 1, 0);

    for (int i = 0; i < n; i++) {
        // 倒序遍历防止重复选取
        for (int w = capacity; w >= weights[i]; w--) {
            dp[w] = max(dp[w], dp[w - weights[i]] + values[i]);
        }
    }

    return dp[capacity];
}

使用示例:

C++
vector<int> weights = {1, 3, 4, 5};
vector<int> values = {1, 4, 5, 7};
int capacity = 7;
int maxValue = knapsack01(weights, values, capacity);  // 返回: 9

5.3 最长公共子序列(LCS)

C++
/**
 * 最长公共子序列(LCS)
 * 时间: O(m × n)
 * 空间: O(m × n)
 * 返回: 最长公共子序列的长度
 */
int longestCommonSubsequence(const string& text1, const string& text2) {
    int m = text1.size(), n = text2.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (text1[i - 1] == text2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    return dp[m][n];
}

5.4 最长递增子序列(LIS)

C++
/**
 * 最长递增子序列(LIS)- 二分优化版
 * 时间: O(n log n)
 * 空间: O(n)
 */
int lengthOfLIS(const vector<int>& nums) {
    if (nums.empty()) return 0;

    vector<int> tails;  // tails[i]表示长度为i+1的递增子序列的最小末尾

    for (int num : nums) {
        auto it = lower_bound(tails.begin(), tails.end(), num);
        if (it == tails.end()) {
            tails.push_back(num);  // 扩展最长子序列
        } else {
            *it = num;  // 替换,保持更小末尾
        }
    }

    return tails.size();
}

5.5 最大子数组和(Kadane算法)

C++
/**
 * 最大子数组和(Kadane算法)
 * 时间: O(n)
 * 空间: O(1)
 */
int maxSubArraySum(const vector<int>& nums) {
    if (nums.empty()) return 0;

    int currentSum = nums[0];
    int maxSum = nums[0];

    for (size_t i = 1; i < nums.size(); i++) {
        // 要么从当前开始,要么延续之前的子数组
        currentSum = max(nums[i], currentSum + nums[i]);
        maxSum = max(maxSum, currentSum);
    }

    return maxSum;
}

6. 数据结构

6.1 链表节点

C++
/**
 * 链表节点定义
 */
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

6.2 二叉树节点

C++
/**
 * 二叉树节点定义
 */
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

6.3 并查集(Union-Find)

C++
/**
 * 并查集(Union-Find)
 * 时间: 均摊O(α(n)),近似O(1)
 * 空间: O(n)
 * 功能: 连通性判断、连通分量计数
 */
struct UnionFind {
    vector<int> parent;  // 父节点
    vector<int> rank;    // 秩(用于按秩合并)
    int count;           // 连通分量数

    UnionFind(int n) : count(n) {
        parent.resize(n);
        rank.resize(n, 0);
        for (int i = 0; i < n; i++) parent[i] = i;
    }

    // 查找根节点(带路径压缩)
    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    // 合并两个集合
    bool unite(int x, int y) {
        int rootX = find(x), rootY = find(y);
        if (rootX == rootY) return false;

        // 按秩合并
        if (rank[rootX] < rank[rootY]) swap(rootX, rootY);
        parent[rootY] = rootX;
        if (rank[rootX] == rank[rootY]) rank[rootX]++;

        count--;
        return true;
    }

    // 判断是否连通
    bool connected(int x, int y) {
        return find(x) == find(y);
    }
};

使用示例:

C++
UnionFind uf(5);  // 5个节点: 0, 1, 2, 3, 4
uf.unite(0, 1);
uf.unite(1, 2);
cout << uf.connected(0, 2);  // true
cout << uf.count;            // 3 (连通分量数)

6.4 Trie树

C++
/**
 * Trie树节点
 */
struct TrieNode {  // struct结构体:自定义复合数据类型
    TrieNode* children[26];
    bool isEnd;
    int count;  // 经过该节点的单词数

    TrieNode() {
        memset(children, 0, sizeof(children));
        isEnd = false;
        count = 0;
    }
};

/**
 * Trie树
 * 时间: 插入/搜索/前缀匹配都是O(m),m为单词长度
 * 空间: O(N × m),N为单词数
 */
class Trie {
private:
    TrieNode* root;

public:
    Trie() { root = new TrieNode(); }

    void insert(const string& word) {
        TrieNode* node = root;
        for (char c : word) {
            int idx = c - 'a';
            if (!node->children[idx]) {
                node->children[idx] = new TrieNode();
            }
            node = node->children[idx];
            node->count++;
        }
        node->isEnd = true;
    }

    bool search(const string& word) {
        TrieNode* node = root;
        for (char c : word) {
            int idx = c - 'a';
            if (!node->children[idx]) return false;
            node = node->children[idx];
        }
        return node->isEnd;
    }

    bool startsWith(const string& prefix) {
        TrieNode* node = root;
        for (char c : prefix) {
            int idx = c - 'a';
            if (!node->children[idx]) return false;
            node = node->children[idx];
        }
        return true;
    }
};

使用示例:

C++
Trie trie;
trie.insert("apple");
trie.insert("app");
cout << trie.search("apple");   // true
cout << trie.search("app");     // true
cout << trie.startsWith("ap");  // true

6.5 线段树

C++
/**
 * 线段树 - 区间和查询 + 单点修改
 * 时间: 查询/修改都是O(log n)
 * 空间: O(4n)
 */
class SegmentTree {
private:
    vector<int> tree;   // 线段树数组
    vector<int> lazy;   // 懒标记数组
    int n;

    void build(const vector<int>& arr, int node, int start, int end) {
        if (start == end) {
            tree[node] = arr[start];
            return;
        }
        int mid = (start + end) / 2;
        build(arr, 2 * node, start, mid);
        build(arr, 2 * node + 1, mid + 1, end);
        tree[node] = tree[2 * node] + tree[2 * node + 1];
    }

    void pushDown(int node, int start, int end) {
        if (lazy[node] != 0) {
            int mid = (start + end) / 2;
            tree[2 * node] += lazy[node] * (mid - start + 1);
            lazy[2 * node] += lazy[node];
            tree[2 * node + 1] += lazy[node] * (end - mid);
            lazy[2 * node + 1] += lazy[node];
            lazy[node] = 0;
        }
    }

    int queryRange(int node, int start, int end, int left, int right) {
        if (left > end || right < start) return 0;
        if (left <= start && end <= right) return tree[node];

        pushDown(node, start, end);
        int mid = (start + end) / 2;
        return queryRange(2 * node, start, mid, left, right) +
               queryRange(2 * node + 1, mid + 1, end, left, right);
    }

    void updatePoint(int node, int start, int end, int idx, int val) {
        if (start == end) {
            tree[node] = val;
            return;
        }
        pushDown(node, start, end);
        int mid = (start + end) / 2;
        if (idx <= mid) updatePoint(2 * node, start, mid, idx, val);
        else updatePoint(2 * node + 1, mid + 1, end, idx, val);
        tree[node] = tree[2 * node] + tree[2 * node + 1];
    }

public:
    SegmentTree(const vector<int>& arr) {
        n = arr.size();
        tree.resize(4 * n);
        lazy.resize(4 * n, 0);
        build(arr, 1, 0, n - 1);
    }

    int query(int left, int right) {
        return queryRange(1, 0, n - 1, left, right);
    }

    void update(int idx, int val) {
        updatePoint(1, 0, n - 1, idx, val);
    }
};

使用示例:

C++
SegmentTree st({1, 3, 5, 7, 9, 11});
cout << st.query(1, 4);  // 3+5+7+9 = 24
st.update(2, 10);        // 将索引2的值改为10
cout << st.query(1, 4);  // 3+10+7+9 = 29

6.6 树状数组(Fenwick Tree)

C++
/**
 * 树状数组(Fenwick Tree / BIT)
 * 时间: 查询/修改都是O(log n)
 * 空间: O(n)
 * 适用: 前缀和查询、单点修改
 */
class FenwickTree {
private:
    vector<int> tree;
    int n;

    int lowbit(int x) { return x & (-x); }

public:
    FenwickTree(int size) : n(size) {
        tree.resize(n + 1, 0);
    }

    // 在索引idx处增加val
    void update(int idx, int val) {
        idx++;
        while (idx <= n) {
            tree[idx] += val;
            idx += lowbit(idx);
        }
    }

    // 查询[0, idx]的和
    int query(int idx) {
        idx++;
        int sum = 0;
        while (idx > 0) {
            sum += tree[idx];
            idx -= lowbit(idx);
        }
        return sum;
    }

    // 查询[left, right]的和
    int query(int left, int right) {
        if (left == 0) return query(right);
        return query(right) - query(left - 1);
    }
};

6.7 LRU缓存

C++
/**
 * LRU缓存
 * 时间: get/put都是O(1)
 * 空间: O(capacity)
 * 实现: 哈希表 + 双向链表
 */
class LRUCache {
private:
    int capacity;
    list<pair<int, int>> cache;  // {key, value}
    unordered_map<int, list<pair<int, int>>::iterator> map;

public:
    LRUCache(int cap) : capacity(cap) {}

    int get(int key) {
        auto it = map.find(key);
        if (it == map.end()) return -1;
        // 移到队首(最近使用)
        cache.splice(cache.begin(), cache, it->second);
        return it->second->second;
    }

    void put(int key, int value) {
        auto it = map.find(key);
        if (it != map.end()) {
            // 更新值并移到队首
            it->second->second = value;
            cache.splice(cache.begin(), cache, it->second);
            return;
        }
        // 插入新元素
        cache.push_front({key, value});
        map[key] = cache.begin();
        // 超出容量,删除最久未使用的
        if (cache.size() > capacity) {
            map.erase(cache.back().first);
            cache.pop_back();
        }
    }
};

7. 回溯算法

7.1 全排列

C++
/**
 * 全排列 - 回溯算法
 * 时间: O(n! × n)
 * 空间: O(n)
 */
void backtrackPermute(vector<int>& nums, vector<bool>& used,
                      vector<int>& current, vector<vector<int>>& result) {
    if (current.size() == nums.size()) {
        result.push_back(current);
        return;
    }

    for (int i = 0; i < nums.size(); i++) {
        if (used[i]) continue;

        used[i] = true;
        current.push_back(nums[i]);
        backtrackPermute(nums, used, current, result);
        current.pop_back();
        used[i] = false;
    }
}

vector<vector<int>> permute(vector<int>& nums) {
    vector<vector<int>> result;
    vector<int> current;
    vector<bool> used(nums.size(), false);
    backtrackPermute(nums, used, current, result);
    return result;
}

使用示例:

C++
vector<int> nums = {1, 2, 3};
vector<vector<int>> result = permute(nums);
// [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]


8. 数学算法

8.1 快速幂

C++
/**
 * 快速幂
 * 时间: O(log exp)
 * 空间: O(1)
 * 计算: (base^exp) % mod
 */
long long fastPow(long long base, long long exp, long long mod) {
    long long result = 1;
    base %= mod;

    while (exp > 0) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }

    return result;
}

使用示例:

C++
cout << fastPow(2, 10, 1000);  // 2^10 % 1000 = 24

8.2 GCD - 最大公约数

C++
/**
 * GCD - 最大公约数(欧几里得算法)
 * 时间: O(log min(a, b))
 * 空间: O(log min(a, b)) 递归栈
 */
int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

// 迭代版
int gcdIterative(int a, int b) {
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

8.3 LCM - 最小公倍数

C++
/**
 * LCM - 最小公倍数
 * 公式: lcm(a, b) = a / gcd(a, b) * b
 */
int lcm(int a, int b) {
    return a / gcd(a, b) * b;
}

8.4 埃氏筛

C++
/**
 * 埃氏筛 - 质数筛法
 * 时间: O(n log log n)
 * 空间: O(n)
 * 返回: isPrime[i]表示i是否为质数
 */
vector<bool> sieve(int n) {
    vector<bool> isPrime(n + 1, true);
    isPrime[0] = isPrime[1] = false;

    for (int i = 2; i * i <= n; i++) {
        if (isPrime[i]) {
            for (int j = i * i; j <= n; j += i) {
                isPrime[j] = false;
            }
        }
    }

    return isPrime;
}

8.5 线性筛(欧拉筛)

C++
/**
 * 线性筛(欧拉筛)
 * 时间: O(n)
 * 空间: O(n)
 * 返回: 质数列表
 */
vector<int> linearSieve(int n) {
    vector<bool> isPrime(n + 1, true);
    vector<int> primes;
    isPrime[0] = isPrime[1] = false;

    for (int i = 2; i <= n; i++) {
        if (isPrime[i]) primes.push_back(i);

        for (int j = 0; j < primes.size() && i * primes[j] <= n; j++) {
            isPrime[i * primes[j]] = false;
            if (i % primes[j] == 0) break;  // 保证每个合数只被最小质因子筛掉
        }
    }

    return primes;
}

使用示例:

C++
vector<int> primes = linearSieve(30);
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]


📝 竞赛编程模板头

C++
#include <bits/stdc++.h>
using namespace std;

// 常用类型定义
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vll;

// 常用宏定义
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define all(x) (x).begin(), (x).end()
#define sz(x) (int)(x).size()
#define rep(i, a, b) for (int i = (a); i < (b); i++)
#define per(i, a, b) for (int i = (b) - 1; i >= (a); i--)

// 竞赛优化
#define fastio ios::sync_with_stdio(false); cin.tie(nullptr);

// 调试输出(本地调试时使用)
#ifdef LOCAL
n#define debug(x) cout << #x << " = " << (x) << endl
#else
#define debug(x)
#endif

int main() {
    fastio;
    // 你的代码
    return 0;
}

💡 使用建议

1. LeetCode 使用方式

C++
// 直接复制需要的模板到 Solution 类中
class Solution {
public:
    // 你的解题代码
};

2. 竞赛使用方式

C++
// 完整复制头文件和需要的模板
#include <bits/stdc++.h>  // 引入头文件
using namespace std;

// 粘贴需要的模板...

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // 解题代码

    return 0;
}

3. 复杂度速查

算法/数据结构 时间复杂度 空间复杂度
快速排序 O(n log n) O(log n)
归并排序 O(n log n) O(n)
二分搜索 O(log n) O(1)
BFS/DFS O(V + E) O(V)
Dijkstra O((V+E) log V) O(V)
并查集 O(α(n)) O(n)
Trie树 O(m) O(N×m)
线段树 O(log n) O(4n)
树状数组 O(log n) O(n)
快速幂 O(log exp) O(1)

模板库持续更新中...