目录
一、引言
计算机算法和数据结构是编程领域的基石,它们为解决各种复杂问题提供了高效的解决方案。本文将汇总视频中涉及的计算机算法和数据结构知识点,并给出相应的 C++ 代码实现。
二、队列与栈
1. 先进先出队列
队列是一种遵循先进先出(FIFO)原则的数据结构。在 C++ 中,可以使用 std::queue
来实现。
#include <iostream>
#include <queue>
int main() {
std::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
while (!q.empty()) {
std::cout << q.front() << " ";
q.pop();
}
std::cout << std::endl;
return 0;
}
2. 后进先出栈
栈是一种遵循后进先出(LIFO)原则的数据结构。在 C++ 中,可以使用 std::stack
来实现。
#include <iostream>
#include <stack>
int main() {
std::stack<int> s;
s.push(1);
s.push(2);
s.push(3);
while (!s.empty()) {
std::cout << s.top() << " ";
s.pop();
}
std::cout << std::endl;
return 0;
}
三、滑动窗口
滑动窗口最大值问题
给定一个数组和一个固定大小的窗口,求每个窗口内的最大值。可以使用双端队列来解决。
#include <iostream>
#include <vector>
#include <deque>
std::vector<int> maxSlidingWindow(std::vector<int>& nums, int k) {
std::vector<int> result;
std::deque<int> dq;
for (int i = 0; i < nums.size(); ++i) {
if (!dq.empty() && dq.front() == i - k) {
dq.pop_front();
}
while (!dq.empty() && nums[dq.back()] < nums[i]) {
dq.pop_back();
}
dq.push_back(i);
if (i >= k - 1) {
result.push_back(nums[dq.front()]);
}
}
return result;
}
四、数组查找
有序数组的二分查找
二分查找是一种在有序数组中查找特定元素的高效算法。
#include <iostream>
#include <vector>
int binarySearch(std::vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
五、动态规划
查找最长递增子序列
使用动态规划算法来查找最长递增子序列。
#include <iostream>
#include <vector>
#include <algorithm>
int lengthOfLIS(std::vector<int>& nums) {
if (nums.empty()) return 0;
std::vector<int> dp(nums.size(), 1);
for (int i = 0; i < nums.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = std::max(dp[i], dp[j] + 1);
}
}
}
return *std::max_element(dp.begin(), dp.end());
}
六、排序与统计
数组中逆序对统计
使用归并排序思想来统计数组中的逆序对。
#include <iostream>
#include <vector>
int mergeSort(std::vector<int>& nums, int left, int right) {
if (left >= right) return 0;
int mid = left + (right - left) / 2;
int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right);
std::vector<int> temp(right - left + 1);
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
count += mid - i + 1;
}
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= right) temp[k++] = nums[j++];
for (i = left, k = 0; i <= right; ++i, ++k) {
nums[i] = temp[k];
}
return count;
}
int reversePairs(std::vector<int>& nums) {
return mergeSort(nums, 0, nums.size() - 1);
}
七、集合操作
1. 快速获取集合重复值
可以使用哈希表来快速获取集合中的重复值。
#include <iostream>
#include <vector>
#include <unordered_set>
std::vector<int> findDuplicates(std::vector<int>& nums) {
std::unordered_set<int> seen;
std::unordered_set<int> duplicates;
for (int num : nums) {
if (seen.find(num) != seen.end()) {
duplicates.insert(num);
} else {
seen.insert(num);
}
}
return std::vector<int>(duplicates.begin(), duplicates.end());
}
2. 快速获取集合最值
可以使用 std::min_element
和 std::max_element
来快速获取集合的最值。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
auto minIt = std::min_element(nums.begin(), nums.end());
auto maxIt = std::max_element(nums.begin(), nums.end());
std::cout << "Min: " << *minIt << ", Max: " << *maxIt << std::endl;
return 0;
}
八、图相关
1. 无向图判环(并查集方法)
#include <iostream>
#include <vector>
class UnionFind {
public:
std::vector<int> parent;
UnionFind(int n) {
parent.resize(n);
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);
int rootY = find(y);
if (rootX == rootY) {
return false;
}
parent[rootX] = rootY;
return true;
}
};
bool hasCycle(int n, std::vector<std::vector<int>>& edges) {
UnionFind uf(n);
for (auto& edge : edges) {
if (!uf.unite(edge[0], edge[1])) {
return true;
}
}
return false;
}
2. 图的连通性问题(并查集)
#include <iostream>
#include <vector>
class UnionFind {
public:
std::vector<int> parent;
UnionFind(int n) {
parent.resize(n);
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];
}
void unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootX] = rootY;
}
}
bool isConnected(int x, int y) {
return find(x) == find(y);
}
};
3. 深度优先搜索(DFS)
#include <iostream>
#include <vector>
void dfs(std::vector<std::vector<int>>& graph, int node, std::vector<bool>& visited) {
visited[node] = true;
std::cout << node << " ";
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
dfs(graph, neighbor, visited);
}
}
}
4. 单源最短路算法:迪杰斯特拉算法
#include <iostream>
#include <vector>
#include <queue>
#include <limits>
using namespace std;
const int INF = numeric_limits<int>::max();
vector<int> dijkstra(const vector<vector<pair<int, int>>>& graph, int start) {
int n = graph.size();
vector<int> dist(n, INF);
dist[start] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, start});
while (!pq.empty()) {
int u = pq.top().second;
int d = pq.top().first;
pq.pop();
if (d > dist[u]) continue;
for (const auto& edge : graph[u]) {
int v = edge.first;
int weight = edge.second;
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
return dist;
}
5. 多源最短路算法:弗洛伊德算法
#include <iostream>
#include <vector>
#include <limits>
using namespace std;
const int INF = numeric_limits<int>::max();
void floydWarshall(vector<vector<int>>& graph) {
int n = graph.size();
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (graph[i][k] != INF && graph[k][j] != INF) {
graph[i][j] = min(graph[i][j], graph[i][k] + graph[k][j]);
}
}
}
}
}
6. 有向图:拓扑排序
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
vector<int> topologicalSort(const vector<vector<int>>& graph) {
int n = graph.size();
vector<int> inDegree(n, 0);
for (int u = 0; u < n; ++u) {
for (int v : graph[u]) {
inDegree[v]++;
}
}
queue<int> q;
for (int i = 0; i < n; ++i) {
if (inDegree[i] == 0) {
q.push(i);
}
}
vector<int> result;
while (!q.empty()) {
int u = q.front();
q.pop();
result.push_back(u);
for (int v : graph[u]) {
if (--inDegree[v] == 0) {
q.push(v);
}
}
}
if (result.size() != n) {
// 存在环
return {};
}
return result;
}
九、数据处理
1. 主数据离散化
#include <iostream>
#include <vector>
#include <algorithm>
vector<int> discretize(vector<int>& nums) {
vector<int> sortedNums = nums;
sort(sortedNums.begin(), sortedNums.end());
auto last = unique(sortedNums.begin(), sortedNums.end());
sortedNums.erase(last, sortedNums.end());
vector<int> result;
for (int num : nums) {
auto it = lower_bound(sortedNums.begin(), sortedNums.end(), num);
result.push_back(it - sortedNums.begin());
}
return result;
}
2. 静态区间最值(RMQ 问题,ST 表)
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
class SparseTable {
private:
vector<vector<int>> st;
vector<int> log2;
public:
SparseTable(const vector<int>& arr) {
int n = arr.size();
int k = log2_floor(n);
st.resize(n, vector<int>(k + 1));
for (int i = 0; i < n; ++i) {
st[i][0] = arr[i];
}
for (int j = 1; (1 << j) <= n; ++j) {
for (int i = 0; i + (1 << j) - 1 < n; ++i) {
st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
log2.resize(n + 1);
for (int i = 2; i <= n; ++i) {
log2[i] = log2[i / 2] + 1;
}
}
int query(int l, int r) {
int j = log2[r - l + 1];
return min(st[l][j], st[r - (1 << j) + 1][j]);
}
private:
int log2_floor(int x) {
return log2(x) / log2(2);
}
};
十、字符串相关
1. 字符串前缀匹配
#include <iostream>
#include <string>
bool isPrefix(const std::string& str, const std::string& prefix) {
if (prefix.length() > str.length()) return false;
for (int i = 0; i < prefix.length(); ++i) {
if (str[i] != prefix[i]) return false;
}
return true;
}
2. 字符串模式匹配(KMP 算法)
#include <iostream>
#include <vector>
#include <string>
std::vector<int> computeLPSArray(const std::string& pat) {
int m = pat.length();
std::vector<int> lps(m, 0);
int len = 0;
int i = 1;
while (i < m) {
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
} else {
if (len != 0) {
len = lps[len - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
std::vector<int> KMPSearch(const std::string& txt, const std::string& pat) {
int n = txt.length();
int m = pat.length();
std::vector<int> lps = computeLPSArray(pat);
std::vector<int> indices;
int i = 0;
int j = 0;
while (i < n) {
if (pat[j] == txt[i]) {
j++;
i++;
}
if (j == m) {
indices.push_back(i - j);
j = lps[j - 1];
} else if (i < n && pat[j] != txt[i]) {
if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
return indices;
}
3. 最长回文子串
#include <iostream>
#include <string>
std::string longestPalindrome(const std::string& s) {
if (s.empty()) return "";
int start = 0, maxLen = 1;
for (int i = 0; i < s.length(); ++i) {
for (int j = i; j < s.length(); ++j) {
int len = j - i + 1;
bool isPalindrome = true;
for (int k = 0; k < len / 2; ++k) {
if (s[i + k] != s[j - k]) {
isPalindrome = false;
break;
}
}
if (isPalindrome && len > maxLen) {
maxLen = len;
start = i;
}
}
}
return s.substr(start, maxLen);
}
十一、总结
本文汇总了视频中涉及的计算机算法和数据结构知识点,并给出了相应的 C++ 代码实现。这些知识点涵盖了队列、栈、滑动窗口、数组查找、动态规划、排序与统计、集合操作、图相关、数据处理和字符串相关等多个方面。掌握这些知识点和代码实现,将有助于提高编程能力和解决实际问题的能力。