防止复制粘贴,代码还是结束之后补上。
这次稍微变难了点,但是主要问题还是函数题你想调试就只能直接提交,然后盲调;或者补出来他隐藏的函数本地调,运行测试这个功能跟没有一样。
函数题
二叉搜索树中的最近公共祖先
我勒个 LCA 不记录父亲,给我整不会了😇,那我只能暴搜了,如果两个点都在一个子树里,就递归往那个子树搜,直到第一次不在同一边,这次的点就是 LCA。
本来 LCA 可以树上倍增,预处理 ,单次查询 ,然后这题强制单次查询最劣可能达到 ,不理解。
int find(Tree T, int val) { if (!T) return 0; else if (T->Key == val) return 1; else return find(T->Left, val) | find(T->Right, val);}
int LCA( Tree T, int u, int v ) { if (!T) return ERROR; // printf(" %d", T->Key); if (find(T->Left, u) && find(T->Left, v)) return LCA(T->Left, u, v); else if (find(T->Right, u) && find(T->Right, v)) return LCA(T->Right, u, v); else if (find(T, u) && find(T, v)) return T->Key; else return ERROR;}先序输出叶结点
直接 dfs 即可。
void PreorderPrintLeaves( BinTree BT ) { if (!BT) return; if (!BT->Left && !BT->Right) printf(" %c", BT->Data); else { PreorderPrintLeaves(BT->Left); PreorderPrintLeaves(BT->Right); }}求二叉树高度
dfs 回溯的时候统计高度,当前结点的高度 = max{左子树高度,右子树高度} + 1。这种回溯时更新状态的做法有个更专业的名字,叫树形dp,是动态规划的一个分支。
int max(int a, int b) { return a > b ? a : b;}
int GetHeight( BinTree BT ) { if (!BT) return 0; else return max(GetHeight(BT->Left) + 1, GetHeight(BT->Right) + 1);}二叉树的遍历
按要求模拟即可。
void InorderTraversal( BinTree BT ) { if (!BT) return; InorderTraversal(BT->Left); printf(" %c", BT->Data); InorderTraversal(BT->Right);}
void PreorderTraversal( BinTree BT ) { if (!BT) return; printf(" %c", BT->Data); PreorderTraversal(BT->Left); PreorderTraversal(BT->Right);}
void PostorderTraversal( BinTree BT ) { if (!BT) return; PostorderTraversal(BT->Left); PostorderTraversal(BT->Right); printf(" %c", BT->Data);}
typedef struct _node { struct TNode *val; struct _node *ne;} Node;Node *h, *t;
int empty() { return h == NULL;}
void push(BinTree val) { Node *p = (Node *)malloc(sizeof(Node)); p->val = val, p->ne = NULL; if (empty()) h = t = p; else t->ne = p, t = p;}
BinTree pop() { Node *p = h; h = h->ne; if (!h) t = NULL; return p->val;}
void LevelorderTraversal( BinTree BT ) { if (!BT) return; push(BT); while (!empty()) { BinTree x = pop(); printf(" %c", x->Data); if (x->Left) push(x->Left); if (x->Right) push(x->Right); }}编程题
这几个题都不是很容易,感觉加点数据量可以去 xcpc 当签到题了。
哈夫曼编码
做一遍哈夫曼算法,求出来最优树的权值。然后只需要检查是不是前缀码以及权值是否和这个最优的相等。
#include <iostream>#include <queue>
using namespace std;
const int N = 64;int f[128];string s[N];
int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int n, m; cin >> n; priority_queue<int, vector<int>, greater<int>> q; for (int i = 1; i <= n; ++i) { char c; int t; cin >> c >> t; f[c] = t; q.emplace(t); } int w = 0; while (q.size() != 1) { int a = q.top(); q.pop(); int b = q.top(); q.pop(); q.emplace(a + b); w += a + b; } cin >> m; while (m--) { int tw = 0; for (int i = 1; i <= n; ++i) { char c; cin >> c >> s[i]; tw += s[i].length() * f[c]; } bool flag = true; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { if (i == j) continue; if (s[j].length() <= s[i].length() && s[j] == s[i].substr(0, s[j].length())) { flag = false; break; } } if (!flag) break; } if (tw != w || !flag) cout << "No" << endl; else cout << "Yes" << endl; } return 0;}是否完全二叉搜索树
先把树构建出来,然后我的判断逻辑是这样的,bfs 入队的时候允许非空的结点的空的儿子入队,出队的时候如果出现 空 结点 …… 空,这种情况相当于前面缺结点了,就判定为不是。
#include <iostream>#include <queue>
using namespace std;
struct Node { int val; Node *ls, *rs;};
Node *insert(Node *u, int val) { if (!u) { u = new Node; u->val = val; u->ls = u->rs = nullptr; return u; } else if (val > u->val) u->ls = insert(u->ls, val); else u->rs = insert(u->rs, val); return u;}
int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int n; cin >> n; Node *tr = nullptr; for (int i = 1; i <= n; ++i) { int val; cin >> val; tr = insert(tr, val); } queue<Node*> q; q.emplace(tr); bool first = true; int flag = 0; while (!q.empty()) { Node *x = q.front(); q.pop(); if (x == nullptr) { if (flag == 0) flag = 1; } else { if (flag == 1) flag = 2; if (first) first = false; else cout << ' '; cout << x->val; q.emplace(x->ls); q.emplace(x->rs); } } cout << endl; cout << (flag != 2 ? "YES" : "NO") << endl; return 0;}完全二叉树的层序遍历
这道题关键应该在于一个小性质,对于一个完全二叉树,子树一定都是完全二叉树;一个结点的两个子树中一定至少有一棵满的(假设左子树一共有 n 层,考虑两棵子树排在最后一层,如果不够 2n,那右子树是满的,如果超过了,那么左子树是满的),左子树一定不比右子树小,而且两棵子树的大小一定相差不超过 2n。因此对于一个序列,先取最右边的为根,然后枚举哪棵子树是满的,满的那棵子树的大小,有且仅有一个组合是满足所有限制的。然后按照算出的子树大小分割剩余的序列,递归生成左右子树。最后再 bfs 一遍输出。
#include <iostream>#include <queue>
using namespace std;
const int N = 40;
struct Node { int val; Node *ls, *rs;};
int a[N];
Node *build(int l, int r) { if (l > r) return nullptr; Node *u = (Node *)malloc(sizeof(Node)); u->val = a[r]; r--; for (int i = 1; i <= 5; ++i) { int lsize = (1 << i) - 1, rsize = r - l + 1 - lsize; if (lsize >= rsize && rsize >= 0 && abs(lsize - rsize) <= (1 << i)) { u->ls = build(l, l + lsize - 1), u->rs = build(l + lsize, r); break; } rsize = (1 << i) - 1, lsize = r - l + 1 - rsize; if (lsize >= 0 && rsize >= 0 && abs(lsize - rsize) <= (1 << i)) { u->ls = build(l, l + lsize - 1), u->rs = build(l + lsize, r); break; } } return u;}
int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); Node *tr = build(1, n); queue<Node*> q; q.emplace(tr); bool first = true; int flag = 0; while (!q.empty()) { Node *x = q.front(); q.pop(); if (x == nullptr) { if (flag == 0) flag = 1; } else { if (flag == 1) flag = 2; if (first) first = false; else cout << ' '; cout << x->val; q.emplace(x->ls); q.emplace(x->rs); } } cout << endl; return 0;}银行排队问题之单队列多窗口服务
我不能理解,题上说
这里假设每位顾客事务被处理的最长时间为60分钟,然后样例给出了 61,如果不管就 wa,如果强制让 p 和 60 取 min 就过了。我只能说诡异。
模拟就行,按照时间遍历顾客,假设现在遍历到第 i 个,开一个数组 ls 维护每个窗口处理完前 i - 1 个顾客需要的时间。考虑当前顾客选择窗口,所有时间小于ti 都是等价的,为了方便处理直接改成 ti,对后来的顾客也没有影响,现在只需要求 。然后 lsidx += ti,更新一下这个窗口的任务,之后继续下一个人。
#include <iostream>
using namespace std;
const int N = 1010, M = 11;
int ls[M], cnt[M]; // last finish tineint t[N], p[N];
int main() { int n, k; scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d%d", &t[i], &p[i]); p[i] = min(p[i], 60); } scanf("%d", &k); int tot = 0, max_t = 0, lst_t = 0; for (int i = 1; i <= n; ++i) { int mn_idx = 1; for (int j = 1; j <= k; ++j) { ls[j] = max(ls[j], t[i]); if (ls[j] < ls[mn_idx]) mn_idx = j; } tot += ls[mn_idx] - t[i]; max_t = max(max_t, ls[mn_idx] - t[i]); ls[mn_idx] += p[i]; cnt[mn_idx]++; } for (int i = 1; i <= k; ++i) lst_t = max(lst_t, ls[i]); printf("%.1f %d %d\n", (double)tot / n, max_t, lst_t); for (int i = 1; i <= k; ++i) { if (i != 1) putchar(' '); printf("%d", cnt[i]); } printf("\n"); return 0;}银行业务队列简单模拟
奇数偶数先单独存一下,然后两个奇数一个偶数一直输出,如果没有了就跳过,直到全输出完。
#include <iostream>#include <queue>
using namespace std;
bool first = true;
void pop(queue<int> &q) { if (!q.empty()) { if (first) first = false; else printf(" "); printf("%d", q.front()); q.pop(); }}
int main() { queue<int> q1, q2; int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) { int t; scanf("%d", &t); if (t & 1) q1.emplace(t); else q2.emplace(t); } int f = 1; while (!q1.empty() || !q2.empty()) { if (f % 3 == 0) pop(q2); else pop(q1); f = (f + 1) % 3; } printf("\n"); return 0;}部分信息可能已经过时







