大家好!欢迎来到第十六期C++面试题系列,今天我们将深入探讨数据结构相关的经典题目。数据结构是面试中的核心内容,掌握这些不仅能提升你的编程能力,还能让你在面试中脱颖而出。😊本文会逐一讲解每个问题,包括算法思路、C++代码实现,以及一些关键细节。文章结构清晰,确保你一步步理解!每个问题都配有详细代码,让我们开始吧!
文章目录
-
-
-
- [🔢 1. 斐波那契数列](#🔢 1. 斐波那契数列)
- [🧱 2. 堆排序](#🧱 2. 堆排序)
- [🏆 3. 锦标赛排序](#🏆 3. 锦标赛排序)
- [🇭🇺 4. 匈牙利算法](#🇭🇺 4. 匈牙利算法)
- [🎒 5. 背包问题](#🎒 5. 背包问题)
- [🔍 6-8. 数论三连](#🔍 6-8. 数论三连)
- [⚡ 9. 快速幂](#⚡ 9. 快速幂)
- [🤖 10. AC自动机](#🤖 10. AC自动机)
- [💼 面试急救包](#💼 面试急救包)
-
-
🔢 1. 斐波那契数列
递归法 (时间复杂度 O ( 2 n ) O(2^n) O(2n),面试慎用!):
cpp
int fib(int n) {
if (n <= 1) return n;
return fib(n-1) + fib(n-2);
}
动态规划 (时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)):
cpp
int fib(int n) {
int a = 0, b = 1;
while (n--) {
int c = a + b;
a = b;
b = c;
}
return a;
}
💡 冷知识 :矩阵快速幂可优化到 O ( log n ) O(\log n) O(logn)!
🧱 2. 堆排序
核心思想:构建大顶堆 → 交换堆顶与末尾元素 → 调整堆
cpp
void heapify(int arr[], int n, int i) {
int largest = i, l = 2*i+1, r = 2*i+2;
if (l < n && arr[l] > arr[largest]) largest = l;
if (r < n && arr[r] > arr[largest]) largest = r;
if (largest != i) {
swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(int arr[], int n) {
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. 锦标赛排序
树形选择排序,适合找出Top K问题:
cpp
vector<int> tournamentSort(vector<int>& arr) {
int n = arr.size();
vector<int> tree(2*n); // 构建满二叉树
for (int i = n; i < 2*n; i++) tree[i] = arr[i-n];
// 初始化比赛树
for (int i = 2*n-2; i > 0; i -= 2)
tree[i/2] = min(tree[i], tree[i+1]);
vector<int> res;
while (res.size() < n) {
res.push_back(tree[1]); // 当前最小值
int idx = 1;
// 更新树路径
while (idx < n) {
idx *= 2;
if (tree[idx] != tree[1]) idx++;
}
tree[idx] = INT_MAX; // 标记已选
while (idx > 1) { // 向上更新
idx /= 2;
tree[idx] = min(tree[2*idx], tree[2*idx+1]);
}
}
return res;
}
🇭🇺 4. 匈牙利算法
二分图最大匹配(DFS实现):
cpp
bool dfs(int u, vector<vector<int>>& graph, vector<int>& match, vector<bool>& vis) {
for (int v : graph[u]) {
if (!vis[v]) {
vis[v] = true;
if (match[v] == -1 || dfs(match[v], graph, match, vis)) {
match[v] = u;
return true;
}
}
}
return false;
}
int hungarian(vector<vector<int>>& graph, int n) {
vector<int> match(n, -1);
int cnt = 0;
for (int i = 0; i < n; i++) {
vector<bool> vis(n, false);
if (dfs(i, graph, match, vis)) cnt++;
}
return cnt;
}
📌 应用场景:任务分配、约会匹配(没错,就是相亲算法!💘)
🎒 5. 背包问题
经典0-1背包(动态规划):
cpp
int knapSack(int W, vector<int>& wt, vector<int>& val) {
int n = wt.size();
vector<vector<int>> dp(n+1, vector<int>(W+1, 0));
for (int i = 1; i <= n; i++) {
for (int w = 1; w <= W; w++) {
if (wt[i-1] <= w)
dp[i][w] = max(val[i-1] + dp[i-1][w-wt[i-1]], dp[i-1][w]);
else
dp[i][w] = dp[i-1][w];
}
}
return dp[n][W];
}
空间优化版(滚动数组):
cpp
int knapSack(int W, vector<int>& wt, vector<int>& val) {
vector<int> dp(W+1, 0);
for (int i = 0; i < wt.size(); i++)
for (int j = W; j >= wt[i]; j--)
dp[j] = max(dp[j], val[i] + dp[j - wt[i]]);
return dp[W];
}
🔍 6-8. 数论三连
算法 | 代码 | 时间复杂度 |
---|---|---|
最大公约数 | int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } |
O ( log ( min ( a , b ) ) ) O(\log(\min(a,b))) O(log(min(a,b))) |
最小公倍数 | int lcm(int a, int b) { return a * b / gcd(a, b); } |
同上 |
质数判断 | bool isPrime(int n) { if(n < 2) return false; for(int i=2; i*i<=n; i++) if(n%i==0) return false; return true; } |
O ( n ) O(\sqrt{n}) O(n ) |
⚡ 9. 快速幂
计算 a b m o d m a^b \mod m abmodm:
cpp
long long fastPow(long long a, long long b, long long m) {
long long res = 1;
a %= m;
while (b) {
if (b & 1) res = (res * a) % m;
a = (a * a) % m;
b >>= 1;
}
return res;
}
🌟 技巧:面试官常考指数取模,记住这个模板!
🤖 10. AC自动机
多模式字符串匹配(Trie树+KMP思想):
cpp
struct TrieNode {
TrieNode* children[26];
TrieNode* fail;
bool isEnd;
TrieNode() : fail(nullptr), isEnd(false) {
memset(children, 0, sizeof(children));
}
};
void insert(TrieNode* root, string word) {
for (char c : word) {
int idx = c - 'a';
if (!root->children[idx])
root->children[idx] = new TrieNode();
root = root->children[idx];
}
root->isEnd = true;
}
void buildAC(TrieNode* root) {
queue<TrieNode*> q;
q.push(root);
while (!q.empty()) {
auto node = q.front(); q.pop();
for (int i = 0; i < 26; i++) {
TrieNode* child = node->children[i];
if (!child) continue;
if (node == root) child->fail = root;
else {
TrieNode* f = node->fail;
while (f && !f->children[i]) f = f->fail;
child->fail = f ? f->children[i] : root;
}
q.push(child);
}
}
}
bool searchAC(TrieNode* root, string text) {
TrieNode* cur = root;
for (char c : text) {
int idx = c - 'a';
while (cur != root && !cur->children[idx])
cur = cur->fail;
if (cur->children[idx])
cur = cur->children[idx];
if (cur->isEnd) return true; // 匹配到任一模式串
}
return false;
}
AC自动机:一次扫描匹配所有关键词的超级侦探🔍
💼 面试急救包
- 手撕代码:堆排序、快速幂必考!
- 复杂度分析:务必说清时间/空间复杂度
- 边界处理:空输入、负数等 corner case
- 优化方向:主动提动态规划空间优化
🎁 🌟如果觉得有用,点个赞吧!👍 收藏本文,面试前翻一翻,上岸更轻松! 如果觉得有用,点赞支持一下,你的鼓励是我持续更新的动力!😊 也欢迎关注我,获取更多"C++上岸"系列干货。下期见!🚀
祝大家offer拿到手软!(๑•̀ㅂ•́)و✧