Template

Frequent Template

Shortest Path最短路径

Dijkstra

class Solution {
public:
    vector<int> getPath(vector<int>& path, int src, int tar) { //nodes from 1 -> n;
        vector<int> nodeSeq;
        int cur = tar;
        while (path[cur] != -1) {
            nodeSeq.emplace_back(cur);
            cur = path[cur];
        }
        nodeSeq.emplace_back(src);
        reverse(nodeSeq.begin(), nodeSeq.end());
        return nodeSeq;
    }
    int networkDelayTime(vector<vector<int>>& times, int n, int src) { //nodes from 1 -> n;
        const int Inf = INT_MAX / 2;
        vector<vector<int>> graph(n, vector<int> (n, Inf));
        for (const auto& edge: times) {
            int from = edge[0] - 1, to = edge[1] - 1, cost = edge[2];
            graph[from][to] = cost;
        }
        for (int i = 0; i < n; ++i) {
            graph[i][i] = 0;
        }

        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
        vector<int> dist(n, Inf);
        vector<bool> visited(n, false);
        vector<int> path(n, -1);
        pq.emplace(0, src - 1);
        dist[src - 1] = 0;
        while (!pq.empty()) {
            pair<int, int> p = pq.top(); pq.pop();
            int cur = p.second;
            if (visited[cur]) {//add visited array to avoid useless traversal
                continue;
            }
            visited[cur] = true;
            for (int i = 0; i < n; ++i) {
                if (dist[i] > dist[cur] + graph[cur][i]) {
                    dist[i] = dist[cur] + graph[cur][i];
                    pq.emplace(dist[i], i);
                    path[i] = cur;
                } 
            }
        }
        vector<int> pathNodes = getPath(path, src - 1);
        for (auto node: pathNodes)
            cout << node + 1 << ' ';

        int maxDistance = *max_element(dist.begin(), dist.end());
        return maxDistance == Inf ? -1 : maxDistance;
    }
};

Floyd

vector<int> getPath();

int Floyd(vector<vector<int>>& times, int n, int src) { //nodes from 1 -> n;
    const int Inf = INT_MAX / 2;
    vector<vector<int>> graph(n, vector<int> (n, Inf));
    for (int i = 0; i < n; ++i) {
        graph[i][i] = 0;
    }
    for (const auto& edge: times) {
        int from = edge[0] - 1, to = edge[1] - 1, cost = edge[2];
        graph[from][to] = cost;
    }

    for (int k = 0; k < n; ++k) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                graph[i][j] = min(graph[i][j], graph[i][k] + graph[k][j]);
            }
        }
    }

    int maxDistance = *max_element(graph[src - 1].begin(), graph[src - 1].end());
    return maxDistance == Inf ? -1 : maxDistance;
}

SPFA

int SPFA(vector<vector<int>>& edges, int n, int src) { //nodes from 1 -> n;
    const int Inf = INT_MAX / 2;
    vector<vector<int>> graph(n, vector<int> (n, Inf));
    for (int i = 0; i < n; ++i) {
        graph[i][i] = 0;
    }
    for (const auto& edge: edges) {
        int from = edge[0] - 1, to = edge[1] - 1, cost = edge[2];
        graph[from][to] = cost; 
    }

    vector<int> dist(n, Inf);
    vector<bool> inQ(n, false);
    dist[src - 1] = 0;
    inQ[src - 1] = true;
    queue<int> Q;
    Q.emplace(src - 1);
    while (!Q.empty()) {
        int cur = Q.front(); Q.pop();
        inQ[cur] = false;
        for (int i = 0; i < n; ++i) {
            if (dist[i] > dist[cur] + graph[cur][i]) {
                dist[i] = dist[cur] + graph[cur][i];
                if (!inQ[i]) {
                    Q.emplace(i);
                    inQ[i] = true;
                }
            }
        }
    }
    int maxDistance = *max_element(dist.begin(), dist.end());
    return maxDistance == Inf ? -1 : maxDistance;
}
```



## Minimum Spanning Tree最小生成树

### Prim

```cpp
int Prim(vector<vector<int>>& edges, int n) {
    const int Inf = INT_MAX / 2;
    vector<vector<int>> graph(n, vector<int> (n, Inf));
    for (int i = 0; i < n; ++i) {
        graph[i][i] = 0;
    }
    for (const auto& edge: edges) {
        int p1 = edge[0] - 1, p2 = edge[1] - 1, cost = edge[2];
        graph[p1][p2] = graph[p2][p1] = cost;
    }
    vector<bool> visited(n, false);
    vector<int> dist(n, Inf);
    dist[0] = 0;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.emplace(0, 0);
    int res = 0;
    int connectedNum = 0;
    while(!pq.empty()) {
        pair<int, int> p = pq.top(); pq.pop();
        int cur = p.second;
        if (visited[cur]) {
            continue;
        }
        ++connectedNum;
        res += p.first;
        visited[cur] = true;
        for (int i = 0; i < n; ++i) {
            if (dist[i] > graph[cur][i]) {
                dist[i] = graph[cur][i];
                pq.emplace(dist[i], i);
            }
        }
    }
    return n == connectedNum ? res : - 1;
}

UnionFind并查集

class UnionFind { 
public:
    UnionFind(int n): rank(n, 1) {
        parent.reserve(n);
        for (int i = 0; i < n; ++i) {
            parent.emplace_back(i);
        }
    }

    bool IsConnected(int x, int y) {
        return find(x) == find(y);
    }

    bool Unite(int x, int y) {
        int rootX = find(x), rootY = find(y);
        if (rootX == rootY) {
            return false;
        } 
        
        if (rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY;
        } else if (rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else {
            parent[rootX] = rootY;
            ++rank[rootY];
        }
        return true;
    }

private:
    int find(int x) {
        if (x != parent[x]) {
            parent[x]  = find(parent[x]);
        }
        return parent[x];
    }

    vector<int> parent;
    vector<int> rank;
};

Kruskal

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

    int find(int i) {
        if (i != parent[i]) {
            parent[i] = find(parent[i]);
        }
        return parent[i];
    }

    bool unite(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            if (rank[rootX] <= rank[rootY]) {
                if (rank[rootX] == rank[rootY]) {
                    ++rank[rootY];
                }
                parent[rootX] = rootY;
            } else {
                parent[rootY] = rootX;
            }
            return true;
        }
        return false;
    }

private:
    vector<int> parent;
    vector<int> rank;
};

int Kruskal(vector<vector<int>>& edges, int n) {
    sort(edges.begin(), edges.end(), [](const vector<int>& edge1, const vector<int>& edge2) {
        return edge1[2] < edge2[2];
    });

    int connectedNum = 1;
    int res = 0;
    UnionFind uf(n);
    for (const auto& edge: edges) {
        int p1 = edge[0] - 1, p2 = edge[1] - 1, cost = edge[2];
        if (uf.unite(p1, p2)) {
            res += cost;
            ++connectedNum;
        }
    }
    return connectedNum == n ? res : -1;
}
int SPFA(vector<vector<int>>& edges, int n, int src) { //nodes from 1 -> n;
    const int Inf = INT_MAX / 2;
    vector<vector<int>> graph(n, vector<int> (n, Inf));
    for (int i = 0; i < n; ++i) {
        graph[i][i] = 0;
    }
    for (const auto& edge: edges) {
        int from = edge[0] - 1, to = edge[1] - 1, cost = edge[2];
        graph[from][to] = cost; 
    }

    vector<int> dist(n, Inf);
    vector<bool> inQ(n, false);
    dist[src - 1] = 0;
    inQ[src - 1] = true;
    queue<int> Q;
    Q.emplace(src - 1);
    while (!Q.empty()) {
        int cur = Q.front(); Q.pop();
        inQ[cur] = false;
        for (int i = 0; i < n; ++i) {
            if (dist[i] > dist[cur] + graph[cur][i]) {
                dist[i] = dist[cur] + graph[cur][i];
                if (!inQ[i]) {
                    Q.emplace(i);
                    inQ[i] = true;
                }
            }
        }
    }
    int maxDistance = *max_element(dist.begin(), dist.end());
    return maxDistance == Inf ? -1 : maxDistance;
}

Segment Tree线段树

区间加法

tag[]表示加法懒标记

//add to the interval block
#include<bits/stdc++.h>

using namespace std;
int n, m;
typedef long long ll;
const int MAXN = 1e5 + 10;
ll arr[MAXN], sum[MAXN<<2], tag[MAXN<<2];

inline int lc(int p) {
    return p << 1;
}

inline int rc(int p) {
    return p << 1 | 1;
}

void pushUp(int p) {
    sum[p] = sum[lc(p)] + sum[rc(p)];
}

void build(int p, int l, int r) {
    if (l == r) {
        sum[p] = arr[l];
        return;
    }
    int mid = ((r - l) >> 1) + l;
    build(lc(p), l, mid);
    build(rc(p), mid + 1, r);
    pushUp(p);
}

void lazy(int p, ll val, int l, int r) {
    tag[p] += val;
    sum[p] += val * (r - l + 1);
}

void pushDown(int p, int l, int r) {
    int mid = ((r - l) >> 1) + l;
    lazy(lc(p), tag[p], l, mid);
    lazy(rc(p), tag[p], mid + 1, r);
    tag[p] = 0;
}

void update(int p, ll val, int updateL, int updateR, int l, int r) {
    if (updateL <= l && r <= updateR) {
        lazy(p, val, l, r);
        return;
    }
    int mid = ((r - l) >> 1) + l;
    if (tag[p] != 0) {
        pushDown(p, l, r);
    }
    if (updateL <= mid) update(lc(p), val, updateL, updateR, l, mid);
    if (updateR > mid) update(rc(p), val, updateL, updateR, mid + 1, r);
    pushUp(p);
}

ll query(int p, int queryL, int queryR, int l, int r) {
    if (queryL <= l && r <= queryR) {
        return sum[p];
    }
    int mid = ((r - l) >> 1) + l;
    if (tag[p] != 0) {
        pushDown(p, l, r);
    }
    ll res = 0;
    if (queryL <= mid) res += query(lc(p), queryL, queryR, l, mid);
    if (queryR > mid) res += query(rc(p), queryL, queryR, mid + 1, r);
    return res;
}
int main() {
    int l, r;
    ll val;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &arr[i]);
    }
    build(1, 1, n);
    while (m--) {
        int choice; cin >> choice;
        if (choice == 1) {
            scanf("%d%d%lld", &l, &r, &val);
            update(1, val, l, r, 1, n);
        } else if (choice == 2) {
            scanf("%d%d", &l, &r);
            printf("%lld\n",query(1, l, r, 1, n));
        }
    }
    return 0;
}

区间乘法和加法

mul[]add[]

#include<bits/stdc++.h>

using namespace std;
int n, m, mod;
typedef long long ll;
const int MAXN = 1e5 + 10;
ll arr[MAXN], sum[MAXN<<2], add[MAXN<<2], mul[MAXN<<2];

inline int lc(int p) {
	return p << 1;
}

inline int rc(int p) {
	return p << 1 | 1;
}

void pushUp(int p) {
	sum[p] = (sum[lc(p)] + sum[rc(p)]) % mod; 
}

void build(int p, int l, int r) {
	mul[p] = 1;
	if (l == r) {
		sum[p] = arr[l];
		return;
	}
	int mid = ((r - l) >> 1) + l;
	build(lc(p), l, mid);
	build(rc(p), mid + 1, r);
	pushUp(p);
}


void pushDown(int p, int l, int r) {
	int mid = ((r - l) >> 1) + l;
	sum[lc(p)] = (sum[lc(p)] * mul[p] + add[p] * (mid - l + 1)) % mod;
	sum[rc(p)] = (sum[rc(p)] * mul[p] + add[p] * (r - mid)) % mod;
	mul[lc(p)] = (mul[p] * mul[lc(p)]) % mod;
	mul[rc(p)] = (mul[p] * mul[rc(p)]) % mod;
	add[lc(p)] = (add[p] + add[lc(p)] * mul[p]) % mod;
 	add[rc(p)] = (add[p] + add[rc(p)] * mul[p]) % mod;
 	
	add[p] = 0;
	mul[p] = 1;
}

void updateMul(int p, ll k, int updateL, int updateR, int l, int r) {
	if (updateL <= l && r <= updateR) {
		add[p] = (add[p] * k) % mod;
		mul[p] = (mul[p] * k) % mod;
		sum[p] = (sum[p] * k) % mod;
		return;
	}
	int mid = ((r - l) >> 1) + l;
	if (add[p] != 0 || mul[p] != 1)  {
		pushDown(p, l, r);
	}
	if (updateL <= mid) updateMul(lc(p), k, updateL, updateR, l, mid);
	if (updateR > mid) updateMul(rc(p), k, updateL, updateR, mid + 1, r);
	pushUp(p); 
}

void updateAdd(int p, ll val, int updateL, int updateR, int l, int r) {
	if (updateL <= l && r <= updateR) {
		add[p] = (add[p] + val) % mod;
		sum[p] = (sum[p] + val * (r - l + 1)) % mod; 
		return;
	}
	int mid = ((r - l) >> 1) + l;
	if (add[p] != 0 || mul[p] != 1) {
		pushDown(p, l, r);
	}
	if (updateL <= mid) updateAdd(lc(p), val, updateL, updateR, l, mid);
	if (updateR > mid) updateAdd(rc(p), val, updateL, updateR, mid + 1, r);
	pushUp(p);
}

ll query(int p, int queryL, int queryR, int l, int r) {
	if (queryL <= l && r <= queryR) {
		return sum[p];
	}
	int mid = ((r - l) >> 1) + l;
	if (add[p] != 0 || mul[p] != 1) {
		pushDown(p, l, r);
	}
	ll res = 0;
	if (queryL <= mid) res += query(lc(p), queryL, queryR, l, mid) % mod;
	if (queryR > mid) res += query(rc(p), queryL, queryR, mid + 1, r) % mod;
	return res % mod;
}

int main() {
	int l, r;
	ll val;
	cin >> n >> m >> mod;
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &arr[i]);
	}
	build(1, 1, n);
	while (m--) {
		int choice; cin >> choice;
		if (choice == 1) {
			scanf("%d%d%lld", &l, &r, &val);
			updateMul(1, val, l, r, 1, n);
		} else if (choice == 2) {
			scanf("%d%d%lld", &l, &r, &val);
			updateAdd(1, val, l, r, 1, n);
		} else if (choice == 3) {
			scanf("%d%d", &l, &r);
			printf("%lld\n",query(1, l, r, 1, n));
		}
	}
	return 0;
}

Binary Indexed Tree数状数组

class BIT {
public:
    BIT(int n) {
        tree.resize(n + 1, 0);
    }
    static int lowBit(int x) {
        return x  & (-x);
    }

    void add(int x, int val) { 
        while (x < tree.size()) {
            tree[x] += val;
            x += lowBit(x);
        }
    }

    int query(int x) { // sum from tree[1] to tree[x].
        int res = 0;
        while (x > 0) {
            res += tree[x];
            x -= lowBit(x);
        }
        return res;
    }
    
    int query(int l, int r) {  // [l, r];
        return query(r) - query(l - 1);
    }
private:
    vector<int> tree; //tree index from 1 -> n
};

Quick Power/Multiply快速幂、快速乘

Quick Power

double binaryExponentiation(double x, long long n) {
    if (n == 0) {
		return 1.0;
    }
    double half = binaryExponentiation(x, n >> 1);
    return n & 1? half * half * x : half * half;
}

double iteration(double x, long long n) {
	double res = 1.0;
    double xContribution = x;
    while (n > 0) {
		if (n & 1) {
            res *= xContribution;
        }
        xContribution *= xContribution;
        n >>= 1;
    }
    return res;
}

Quick Multiply

long long quickMul(long long x, long long y) {
    long long res = 0;
    while (y != 0) {
        if (y & 1) {
            res += x;
        }
        x += x;
        y >>= 1;
    }
    return res;
}

数组排序

  1. 插入排序
  2. 选择排序
  3. 冒泡排序
  4. 快速排序
  5. 归并排序
void insertSort(vector<int>& nums) {
    for (int i = 0; i < nums.size() - 1; ++i) {
        int val = nums[i + 1];
        int j = i + 1;
        while (j > 0 && nums[j - 1] > val) {
            nums[j] = nums[j - 1];
            --j;
        }
        nums[j] = val;
    }
}

void selectSort(vector<int>& nums) {
    for (int i = 0; i < nums.size() - 1; ++i) {
        int minIndex = i;
        for (int j = i + 1; j < nums.size(); ++j) {
            if (nums[j] < nums[minIndex]) {
                minIndex = j;
            }
        }
        swap(nums[minIndex], nums[i]);
    }
}

void bubbleSort(vector<int>& nums) {
    for (int i = nums.size() - 1; i >= 0; --i) {
        bool isSorted = true;
        for (int j = 0; j < i; ++j) {
            if (nums[j] > nums[j + 1]) {
                swap(nums[j], nums[j + 1]);
                isSorted = false;
            }
        }
        if (isSorted) {
            break;
        }
    }
}

// 快速排序
int partiion(vector<int>& nums, int l, int r) {
    int pivotValue = nums[r];
    int p = l;
    //保证p左边的值都小于pivotValue
    for (int i = l; i < r; ++i) {
        if (nums[i] < pivotValue) {
            swap(nums[i], nums[p++]);
        }
    }
    //将pivotValue放到中间的位置,此时 左边都小于,右边都大于。
    swap(nums[p], nums[r]); 
    return p;
}

// find pivot, divide and conqure recursively
void quickSort(vector<int>& nums, int l, int r) {
    if (l >= r) {
        return ;
    }

    int pivotIndex = rand() % (r - l + 1) + l;
    swap(nums[r], nums[pivotIndex]);
    int m = partiion(nums,  l, r);
    quickSort(nums, l, m);
    quickSort(nums, m + 1, r);
}

vector<int> quickSort(vector<int>& nums) {
    quickSort(nums, 0, nums.size() - 1);
    return nums;
}

// 归并排序
// 		递归向下,保证左右两部分l、r数组有序,再进行归并。
// 		和quickSort不同的是,这个先递归。利用
// 		归并,要用到一个临时数组temp
void headSort(vector<int>& nums, vector<int>& temp, int l, int r) {
    if (l >= r) {
        return;
    }
    int m = (r - l) / 2 + l;
    headSort(nums, temp, l, m);
    headSort(nums, temp, m + 1, r);

    int ptr = l;
    int lPtr = l, rPtr = m + 1;
    while (lPtr <= m && rPtr <= r) {
        if (nums[lPtr] < nums[rPtr]) {
            temp[ptr++] = nums[lPtr++];
        } else {
            temp[ptr++] = nums[rPtr++];
        }
    }
    while (lPtr <= m) {
        temp[ptr++] = nums[lPtr++];
    }
    while (rPtr <= r) {
        temp[ptr++] = nums[rPtr++];
    }
    copy(temp.begin() + l, temp.begin() + r + 1, nums.begin() + l);
}

vector<int> sortArray(vector<int>& nums) {
    vector<int> temp(nums.size());
    headSort(nums, temp, 0, nums.size() - 1);
    return nums;
}

链表排序

  • 归并排序
  • 堆排序:但需要指定比较器,稍麻烦。
// mergeSort
// 1. 找中点
// 2. 划分l、r两部分链表,设置middle的next为nullptr
// 3. 递归分割l、r两部分,直到l、r两部分有序
// 4. 向上归并
ListNode* findMiddle(ListNode* head) {
    if (head == nullptr || head->next == nullptr) {
        return head;
    }
    ListNode dummy(0, head);
    ListNode* fast = &dummy;
    ListNode* slow = &dummy;
    while (fast->next != nullptr && fast->next->next != nullptr) {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

ListNode* merge(ListNode* head1, ListNode* head2) {
    ListNode dummy;
    ListNode* tail = &dummy;
    while (head1 != nullptr && head2 != nullptr) {
        if (head1->val < head2->val) {
            tail->next = head1;
            head1 = head1->next;
        } else {
            tail->next = head2;
            head2 = head2->next;
        }
        tail = tail->next;
    }
    if (head1 != nullptr) {
        tail->next = head1;
    } else {
        tail->next = head2;
    }
    return dummy.next;
}

ListNode* mergeSort(ListNode* head) {
    if (head == nullptr || head->next == nullptr) {
        return head;
    }

  	// 找中点,并划分l、r两部分
    ListNode* middle = findMiddle(head);
    ListNode* left = head, *right = middle->next;
    middle->next = nullptr;
  
  	// 让l、r两部分有序
    left = mergeSort(left);
    right = mergeSort(right);
  
  	// 有序后,进行归并
    return merge(left, right);
}

Heap、堆、堆排序

核心操作是heapify,分为在数组最后的heapifyUp和在数组0下标进行的heapifyDown;

  • Add时,插入到尾部,再heapifyUp
  • delete时,将头部和尾部置换,为新的头部进行heapifyDown
class MinHeap {
private:
    std::vector<int> heap;

    // 从指定位置开始向上递归调整堆,维护小顶堆性质
    void heapifyUp(int index) {
        if (index == 0) {
            return;
        }

        int parent = getParent(index);
        if (heap[index] < heap[parent]) {
            std::swap(heap[index], heap[parent]);
            heapifyUp(parent); // 递归调整
        }
    }

    // 从指定位置开始向下递归调整堆,维护小顶堆性质
    void heapifyDown(int index) {
        int leftChild = getLeftChild(index);
        int rightChild = getRightChild(index);
        int smallest = index;

        if (leftChild < heap.size() && heap[leftChild] < heap[smallest]) {
            smallest = leftChild;
        }

        if (rightChild < heap.size() && heap[rightChild] < heap[smallest]) {
            smallest = rightChild;
        }

        if (smallest != index) {
            std::swap(heap[index], heap[smallest]);
            heapifyDown(smallest); // 递归调整
        }
    }

    inline int getParent(int index) {
        return (index - 1) / 2;
    }

    inline int getLeftChild(int index) {
        return 2 * index + 1;
    }

    inline int getRightChild(int index) {
        return 2 * index + 2;
    }

public:
    // 构造函数,数组构造时,一个一个添加
    MinHeap() {}
    MinHeap(const vector<int>& nums) {
        for (const auto&num: nums) {
            add(num);
        }
    }


    // 添加元素
    void add(int value) {
        heap.push_back(value);
        heapifyUp(heap.size() - 1);
    }

    // 弹出堆顶元素
    int pop() {
        if (heap.empty()) {
            throw std::out_of_range("Heap is empty");
        }

        int top = heap[0];
        heap[0] = heap.back();
        heap.pop_back();
        heapifyDown(0);

        return top;
    }

    // 获取堆顶元素(不弹出)
    int top() const {
        if (heap.empty()) {
            throw std::out_of_range("Heap is empty");
        }
        return heap[0];
    }

    // 获取堆的大小
    size_t size() const {
        return heap.size();
    }

    // 判断堆是否为空
    bool empty() const {
        return heap.empty();
    }

};

C++中的优先队列

这块有点反直觉说实话

#include <iostream>
#include <queue> // 包含 priority_queue 头文件
#include <vector>

using namespace std;
// 定义一个结构体
struct MyStruct {
    int value;

    // 重载 operator<
    // C++的priority_queue的默认是最大堆,最优先的在堆顶,
    // 意思是,堆顶元素的operator<函数,对于其他非顶元素,都为false。
    bool operator<(const MyStruct& other) const {
        // 在这里实现自定义的比较逻辑
        return value < other.value;
    }
};

int main() {
    // 定义一个自定义比较器结构体,如果需要的话
    struct MyComparator {
        bool operator()(const MyStruct& a, const MyStruct& b) const {
            return a.value < b.value; // >小顶堆;<大顶堆
        }
    };

    // 使用自定义的结构体类型和比较器创建优先队列
    std::priority_queue<MyStruct, vector<MyStruct>, MyComparator> pq;
//    std::priority_queue<MyStruct> pq;

    // 添加元素到优先队列
    pq.push({5});
    pq.push({10});
    pq.push({3});

    // 弹出并输出队列中的元素
    while (!pq.empty()) {
        std::cout << pq.top().value << " ";
        pq.pop();
    }

    return 0;
}

KMP

找到所有匹配子串的位置


vector<int> findAllSubStrPosition(const string& s, const string& subStr) {
    int n = subStr.size();
    vector<int> next(n, 0);
    // next[j]代表[0,j]这个子串的前后相同部分的长度
    // 也代表在j + 1匹配失败时,下一个尝试匹配的位置。
    for (int i = 1, j = 0; i < subStr.size(); ++i) {
        while (j != 0 && subStr[j] != subStr[i]) {
            j = next[j - 1];
        }
        if (subStr[i] == subStr[j]) {
            ++j;
        }
        next[i] = j;
    }

    vector<int> allPosition;
    for (int i = 0, j = 0; i < s.size(); ++i) {
        // j的位置是尝试匹配的位置,不匹配则需要返回到next[j - 1](这个也就是下一个尝试的位置)
        // 举例 s="abab-ababe" subStr="ababe", 其中next为[0, 0, 1, 2, 0]
        // 正常匹配,关键位置举例,此时i、j位置如下
        //             i
        //             |
        // a  b  c  d  -  a  b  a  b  e
        // a  b  a  b  e
        //             |
        //             j
        // 此时尝试匹配e和-,会匹配失败,子串的next为[0, 0, 1, 2, 0],
        // 即在e尝试失败时,需要在已经匹配的部分(即以j - 1结尾的前后部分,这里为2)找共同部分, 如下
        //             i
        //             |
        // a  b  c  d  -  a  b  a  b  e
        // a  b  a  b  e
        //       |
        //       j
        // 此时还是匹配失败,就只能跳到0了(next[2 - 1] = 0)
        while (j != 0 && subStr[j] != s[i]) {
            j = next[j - 1];
        }
        if (s[i] == subStr[j]) {
            ++j;
            if (j == subStr.size()) {
                allPosition.emplace_back(i - j + 1);
            }
        }
    }

    return allPosition;
}

前缀树

class Trie {
public:
    Trie(): isEnd(false) {}
    
    void insert(const string& word) {
        Trie* curr = this;
        for (int i = 0; i < word.size(); ++i) {
            if (!curr->next.count(word[i])) {
                curr->next[word[i]] = new Trie;
            }
            curr = curr->next[word[i]];
        }
        curr->isEnd = true;
    }
    
    bool search(const string& word) {
        Trie* p = searchPtr(word);
        return p != nullptr && p->isEnd;
    }   
    
    bool startsWith(const string& prefix) {
        return searchPtr(prefix) != nullptr;
    }
    
private:
    Trie* searchPtr(const string& prefix) {
        Trie* curr = this;
        for (int i = 0; i < prefix.size(); ++i) {
            if (!curr->next.count(prefix[i]))
                return nullptr;
            curr = curr->next[prefix[i]];
        }
        return curr;
    }
    unordered_map<char, Trie*> next;
    bool isEnd;
};

缓存淘汰

LRU

// 要点:
// 1. 哈希表加速node检索
// 2. 从头插,从尾删,保证顺序
class LRUCache {
public:
    LRUCache(int capacity): capacity(capacity) {}
    
    int get(int key) {
        // 不存在直接返回
        auto it = map.find(key);
        if (it == map.end()) {
            return -1;
        }

        // 存在则提出来放头部
        int value = it->second->second;
        updatePosition(key, value);
        return value;
    }
    
    void put(int key, int value) {
        // 存在,提出来放头部并修改value
        auto it = map.find(key);
        if (it != map.end()) {
            updatePosition(key, value);
        } else {  // 不存在,放入;放入前检查容量,不足则弹出尾部。
            insertNewNode(key, value);
        }
    }
private:
    list<pair<int, int>> nodes;
    unordered_map<int, list<pair<int, int>>::iterator> map; 
    int capacity;

    void insertNewNode(int key, int value) {
        if (full()) {
            pop();
        }
        putIn(key, value);
    }

    void updatePosition(int key, int value) {
        dropOut(key);
        putIn(key, value);
    }

    // 尾部弹出
    void pop() {
        auto it = --nodes.end();
        auto key = it->first;
        map.erase(key);
        nodes.erase(it);
    }

    // 放入头部,操作map和list。
    void putIn(int key, int value) {
        auto it = nodes.emplace_front(key, value);
        map[key] = nodes.begin();
    }

    // 删除节点,操作map和list。
    void dropOut(int key) {
        auto it = map.find(key)->second;
        map.erase(key);
        nodes.erase(it);
    }
    
    bool full() {
        return map.size() == capacity;
    }
};

LFU

struct Node{
    int key;
    int value;
    int frequency;
    Node(int key, int value, int frequency): key(key), value(value), frequency(frequency) {}
};

// 要点:
// 1. 通过minimumFrequency记录最小频率,避免pop时遍历frequencyMap。
// 2. 维护最小频率,只需考虑这两种情况。因为不主动删除,只在满时pop,所以满时要么插入新(为1),要么提高(n + 1);
//      1. 插入新节点,更新为1。 
//      2. 提升频率,最小频率链表为空时提升为。
// 3. 每个链表,从头插,从尾删,保证频率相同时,删除最先插入的。
class LFUCache {
public:

    LFUCache(int capacity): capacity(capacity), minimumFrequency(0) {}

    int get(int key) {
        // 不存在返回错误
        auto it = map.find(key);
        if (it == map.end()) {
            return -1;
        }
        // 存在,提升频率
        int value = it->second->value;
        incrementFrequency(key, value);
        return value;
    }

    void put(int key, int value) {
        // 不存在,插入频率为1的链表,注意满时pop
        auto it = map.find(key);
        if (it == map.end()) {
            insertNewNode(key, value);
        } else { // 存在,提升频率
            incrementFrequency(key, value);
        }
    }

private:
    unordered_map<int, std::list<Node>> frequencyMap;
    unordered_map<int, std::list<Node>::iterator> map;
    int minimumFrequency; // 频率更新情况:1. 插入新节点,更新为1。 2. 提升频率,最小频率链表为空时提升。
    int capacity;

private:

    bool full() {
        return this->map.size() == this->capacity;
    }

    void insertNewNode(int key, int value) {
        if (full()) {
            if (this->capacity < 0) {
                return ;
            }
            pop();
        }
        insertNode(key, value, 1);
        this->minimumFrequency = 1; // 1. 插入新节点,更新为1。
    }


    // 弹出频率最低的节点。
    void pop() {
        int key = frequencyMap[minimumFrequency].back().key;
        removeNode(key);
    }


    // 删除节点:删除map和frequcnyMap信息,但未更新频率
    void removeNode(int key) {
        removeFromFrequencyMap(key);
        map.erase(key);
    }


    // 更新频率:涉及value更新、map指向更新、frequency频率更新
    void incrementFrequency(int key, int value) {
        Node d = *(map.find(key)->second);
        removeNode(key);
        insertNode(d.key, value, d.frequency + 1);
        if (!frequencyMap.count(minimumFrequency)) {// 2. 提升频率,原链表为空时提升。
            ++minimumFrequency;
        }
    }

    // 只操作frequecnyMap删除key,并删除空链表
    void removeFromFrequencyMap(int key) {
        auto it = map.find(key)->second;
        int frequency = it->frequency;
        frequencyMap[frequency].erase(it);
        if (frequencyMap[frequency].empty()) {
            frequencyMap.erase(frequency);
        }
    }

    // 将node插入到map和frequecnyMap
    void insertNode(int key, int value, int frequency) {
        auto it = frequencyMap[frequency].emplace_front(key, value, frequency);
        map[key] = frequencyMap[frequency].begin();
    }
};

Template
https://messenger1th.github.io/2024/07/24/LeetCode/Template/
作者
Epoch
发布于
2024年7月24日
许可协议