记录 | 大学里的最后一段时光 #日记楼
Vanitas Vanitatum Et Omnia Vanitas.
虚空的虚空,一切尽为虚空。《般若波罗蜜多心经》亦有言:“观自在菩萨,行深般若波罗蜜多时,照见五蕴皆空,度一切苦厄”。
古今中外,英雄豪杰无不如过江之鲫,于兴盛之时,凭天时地利人和,独领风骚,傲立潮头。殊不知千年之后,虽有“樯橹灰飞烟灭”之气魄,亦不免消失于滚滚历史洪流。
泛泛之辈如我,唯有专注于当下,珍惜自我所有之物,珍惜身边亲近的人,默默地走完本科的最后一段旅程。2025 年 06 月至 2026 年 06 月,我愿在此处不定期地记录下属于自己的一切。
一切皆空,唯有当下愈加贵重。万事喧嚣,愿有一方清静独处之处。愿此处小楼能成为承载我接下来一年的喜怒哀乐,愿自己能够在互联网的一角,留下属于自己的一点点痕迹。
开楼就用我最喜欢的一部动画《可塑性记忆 (プラスチックメモリス)》中的题词送给大家,也送给自己:

提示:可能有时候 lz 会有很负面的情绪,或者不恰当的表述,先向大家表示抱歉,如果楼主说了什么不太好的话或者令大家伤心的话,提示一下 lz 或者屏蔽楼主就好了,先向大家表示歉意,对不起,谢谢大家 🥰
楼里会有什么?
- 可愛いアイラちゃん
- 各种可能的动漫截图
- 每天的生活
- 风景图?周边地图?
- 🐷 😋 🤡
- lz 的焦虑和不安 (很抱歉,有时候控制不了自己 🥲)
- 可能的焦虑传播 (对不起,请一定要提醒 lz 删除(私信发帖都可以))
- 可能的压力和不安
cy ![]()
是新日记楼!
祝 lz 生活顺利🥹
长恨此身非我有 何时忘却营营
开篇先给出自己的假期计划吧!
古人有云:“取法乎上,仅得其中。取法乎中,仅得其下。”所以目标要兼具挑战性和可行性。
暑假的三个月打算:
上午 7:00 左右起床
上午:leetcode,复习数据结构,与其他 408 科目,顺序打算为数据结构 -> 计算机组成 -> 操作系统 -> 计算机网络。这些科目アイラちゃん在期末都是 90 分左右,因此希望会顺利一些 QAQ,为考研/推免都做好两手准备 🫠
中午/下午:做实验室实习的项目/阅读需要阅读的论文,或者在没有活的时候做一做 15445/6.824,学习 C++/Go。毕竟有希望就要去争取!
晚上:继续复习高数/线代。等到线性代数复习结束后再开概率论和数理统计。并且最后复习一些单词(不过英语应该不需要太担心,アイラちゃん很努力地通过了 Toefl, R25L25S25W26!)
希望自己能完成这个暑假的计划,fight on!!!
cy ![]()
アイラちゃん(指插图中的艾拉)今日もちょ可愛いです 🥰

🥰
アイラちゃん 🥰 🥰
艾拉可爱捏
如果能让アイラちゃん做我的彼女我就算住大别野也愿意口牙 ![]()
2025 年 5 月 30 日 星期五 天气:晴/多云
上午刷 leetcode,复习了一下 dijkstra 算法,正好今天的每日一题也是 dijkstra 算法~
C++
class Solution {
int n;
public:
void bfs(const vector<vector<int>> & graph, priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> & pq, vector<int> & distance, vector<int> & visited, const int & node) {
visited = vector<int>(n, 0);
pq.emplace(0, node);
visited[node] = 1;
distance[node] = 0;
while(!pq.empty()) {
const auto [dist, cur] = pq.top();
pq.pop();
for(const auto & adj: graph[cur]) {
if(distance[adj] > distance[cur] + 1) {
distance[adj] = distance[cur] + 1;
pq.emplace(distance[adj], adj);
}
}
}
}
int closestMeetingNode(vector<int>& edges, int node1, int node2) {
n = edges.size();
vector<vector<int>> graph(n);
for(int i = 0; i < n; i++) {
if(edges[i] == -1) continue;
graph[i].emplace_back(edges[i]);
}
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
vector<int> distance1(n, INT_MAX / 2);
vector<int> distance2(n, INT_MAX / 2);
vector<int> visited;
bfs(graph, pq, distance1, visited, node1);
bfs(graph, pq, distance2, visited, node2);
// Get the distance. Then check the answer.
int ans_dist = INT_MAX / 2;
int ans = -1;
for(int i = 0; i < n; i++) {
int tmp_ans = max(distance1[i], distance2[i]);
if(ans_dist > tmp_ans) {
ans_dist = tmp_ans;
ans = i;
}
else if(ans_dist == tmp_ans) {
ans = min(ans, i);
}
}
return ans == INT_MAX / 2 ? -1 : ans;
}
};
C++
class Graph {
vector<vector<pair<int,int>>>graph;
vector<int> visited;
vector<int> distance;
int n;
public:
Graph(int n, vector<vector<int>>& edges) {
graph = vector<vector<pair<int,int>>>(n);
for(const auto & edge: edges) {
int from = edge[0], to = edge[1], edgeCost = edge[2];
graph[from].emplace_back(to, edgeCost);
}
Graph::n = n;
}
void addEdge(vector<int> edge) {
int from = edge[0], to = edge[1], edgeCost = edge[2];
graph[from].emplace_back(to, edgeCost);
}
int shortestPath(int node1, int node2) {
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
visited = vector<int>(n, 0);
distance = vector<int>(n, INT_MAX / 2);
pq.emplace(0, node1);
distance[node1] = 0;
while(!pq.empty()) {
const auto [dist, cur] = pq.top();
pq.pop();
if(visited[cur]) continue;
visited[cur] = 1;
for(const auto & adj: graph[cur]) {
const auto [adj_to, adj_w] = adj;
if(distance[adj_to] > distance[cur] + adj_w) {
distance[adj_to] = distance[cur] + adj_w;
pq.emplace(distance[adj_to], adj_to);
}
}
}
return distance[node2] == INT_MAX / 2 ? -1 : distance[node2];
}
};
/**
* Your Graph object will be instantiated and called as such:
* Graph* obj = new Graph(n, edges);
* obj->addEdge(edge);
* int param_2 = obj->shortestPath(node1,node2);
*/
C++
constexpr int directions[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
class Solution {
public:
int minTimeToReach(vector<vector<int>>& moveTime) {
// [dist, x, y];
priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, greater<tuple<int,int,int>>> pq;
pq.emplace(0, 0, 0);
int rows = moveTime.size(), cols = moveTime[0].size();
vector<vector<int>> distance(rows, vector<int>(cols, INT_MAX / 2));
vector<vector<int>> visited(rows, vector<int>(cols, 0));
distance[0][0] = 0;
while(!pq.empty()) {
const auto [dist, x, y] = pq.top();
pq.pop();
if(visited[x][y]) continue;
visited[x][y] = 1;
for(int i = 0; i < 4; i++) {
int nx = x + directions[i][0], ny = y + directions[i][1];
if(nx >= 0 && nx < rows && ny >= 0 && ny < cols) {
int temp_distance = max(dist, moveTime[nx][ny]) + (x+y) % 2 + 1;
if(temp_distance < distance[nx][ny]) {
distance[nx][ny] = temp_distance;
pq.emplace(temp_distance, nx, ny);
}
}
}
}
return distance[rows - 1][cols - 1];
}
};
跟着 灵神的题单 走感觉有进步的说!
然后折磨アイラちゃん四天只睡了 16 个小时的 PPG 算法也算是成功实现了,并且确实收敛的速度更快,只是为什么稳定性不好呢 QAQ
下午上数据库原理课,听不懂事务系统 🐷 时间戳控制事务法和 2PL 法更是稀里糊涂 🫠 后面暑假再仔细看看吧~反正不考
晚上学了一下 Go,这门语言还是很有属于自己的风范的,感觉有集百家之长的特性,希望我能稍微掌握一下吧~(这也是兴趣的一部份呢)
最后,提前祝大家晚安好梦的说! 🥰 也祝大家期末顺利!
口瓜怎么日记帖被拿下了 🥲 5 月 30 日的日记贴变成垃圾消息被 Akismet ちゃん拿下了 🥺
是不是主包发 leetcode 题目和代码重复性太高被拿下了 🫠

アイラちゃん 我们土塬貌似是这样的🤔不时会出现这种吞帖的情况
感觉可以向站务提出说明?
站务应该会看到的,就不再单独麻烦他们了 🥺
akismet ちゃん好严厉,有坏坏的大姐姐感觉 🤣
アイラちゃん 豪德 🫠
好饿,出去觅食了 🐖
好耶,帖子回来啦 🥰
谢谢站务 😘
有 C/C++ 基础看起一门新的语言还是很快的,只是迫切地需要熟练度
从例子入手后再去仔细地阅读语法,希望这样能够快速入门 Go, 然后尝试 6.824
p.s.现在变成 6.5840 了,待我学会 go+ 有时间后尝试一下 😋
每日一题 还是可以 Dijkstra 的,毕竟 Dijkstra 就是 BFS 中的队列->优化队列而已~
坐标变换让我成为 🐖
C++-1 (Dijkstra)
class Solution {
public:
int n;
int CheckTransfer(int nums, vector<vector<int>> & board) {
int row, col;
if(nums % n == 0) {
row = n - nums / n;
if(row % 2 != n % 2) {
col = n-1;
}
else {
col = 0;
}
} else {
row = n - 1 - nums / n;
if(row % 2 != n % 2) {
col = (nums % n) - 1;
}
else {
col = n - (nums % n);
}
}
// // ** debug **
// cout << nums << " at: (" << row << " ," << col << ")\n";
return board[row][col];
}
int snakesAndLadders(vector<vector<int>>& board) {
// Build Matrix.
n = board.size();
vector<int> distance(n*n+1, INT_MAX / 2);
vector<int> visited(n*n+1, 0);
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
pq.emplace(0,1);
distance[1] = 0;
while(!pq.empty()) {
// BFS to get the adjacent point.
const auto [dist, cur] = pq.top();
pq.pop();
if(visited[cur]) continue;
visited[cur] = 1;
for(int i = cur + 1; i <= min(cur + 6, n * n); i++) {
int transfer = CheckTransfer(i, board);
int adj = transfer == -1 ? i : transfer;
if(distance[adj] > distance[cur] + 1) {
distance[adj] = distance[cur] + 1;
pq.emplace(distance[adj], adj);
}
}
}
return distance[n * n] == INT_MAX / 2 ? -1 : distance[n * n];
}
};
C++-2 (BFS)
class Solution {
public:
int n;
int CheckTransfer(int nums, vector<vector<int>> & board) {
int row, col;
if(nums % n == 0) {
row = n - nums / n;
if(row % 2 != n % 2) {
col = n-1;
}
else {
col = 0;
}
} else {
row = n - 1 - nums / n;
if(row % 2 != n % 2) {
col = (nums % n) - 1;
}
else {
col = n - (nums % n);
}
}
// // ** debug **
// cout << nums << " at: (" << row << " ," << col << ")\n";
return board[row][col];
}
int snakesAndLadders(vector<vector<int>>& board) {
// Build Matrix.
n = board.size();
vector<int> visited(n*n+1, 0);
queue<pair<int,int>> q;
q.emplace(1, 0);
while(!q.empty()) {
// BFS to get the adjacent point.
const auto [cur, dist] = q.front();
q.pop();
visited[cur] = 1;
for(int i = cur + 1; i <= min(cur + 6, n * n); i++) {
int transfer = CheckTransfer(i, board);
int adj = transfer == -1 ? i : transfer;
if(visited[adj]) continue;
if(adj == n * n) return dist + 1;
visited[adj] = 1;
q.emplace(adj, dist + 1);
}
}
return -1;
}
};
成就 badges

不知不觉三个月了,希望有点进步的说
被 xiong 器裹挟的アイラちゃん

今天是端午节,祝塬友们端午快乐!
也祝 @萨卡兹雇佣兵 生日快乐 🥰
アイラちゃん 谢谢泥喵
(话说我也谢了泥好多次了 🤪)
惊觉一门课下周四有随堂考还有 40% 的分数
天塌了,我说怎么这门课没有大作业,原来是今天跟我说改成随堂考了
好好好 🥺
发挥优良传统,一支笔,一个 graffiti,一个晚上,一个奇迹 🐖
アイラちゃん 集百家之长的特性
好乐,难得见一个不骂的
2025 年 5 月 31 日
今天是五月的最后一天!端午假期快乐!
惊觉一门课下周四有随堂考还有 40% 的分数
天塌了,我说怎么这门课没有大作业,原来是今天跟我说改成随堂考了
前情提要⬆️
于是战复习,复习模型压缩,剪枝,量化策略,复习 TPU 脉动阵列模型,数据流不变方式复用比,amdahl 定理,并行加速比 😴
不过已经复习完一半了!明天就可以复习结束的说!
明天可能要下大暴雨了,真讨厌下雨啊,每次鞋都会湿完,但是还是得来图书馆的,在宿舍只想睡觉就好了 🐖
骑士团和狐狸小队的麻麻们

最后,祝大家晚安好梦~
口瓜,已经下雨了,怎么回事口牙
アイラちゃん 上海怎么天天下雨 ![]()
神秘小维 江淮气旋 + 梅雨=暴雨 🥲

明天的雨势更加猛烈 😵💫

2929. 给小朋友们分糖果 II (1701M)(2025.06.01)
数学题~ 祝大家儿童节快乐 ![]()
Go
func distributeCandies(n int, limit int) int64 {
var ans int64
ans = 0
for i := 0; i <= min(limit, n); i++ {
ans = ans + int64(max(int64(min(limit, n-i)) - int64(max(n-i-limit, 0))+1, 0))
}
return ans
}
C++
class Solution {
public:
long long distributeCandies(int n, int limit) {
long long ans = 0;
for(int i = 0; i <= min(limit, n); i++) {
ans += (long long)max(min(limit, n-i) - max(n-i-limit, 0) + 1, 0);
}
return ans;
}
};
神秘小维 正在宾馆里躲雨 ![]()
此人不语,只是一味地在门里生产废料。
上午复习完了周四的考试,实现了昨天在 神秘小维的赛博小窝 的誓言 ![]()
借你吉言,明天一定一定认真复习 🫡
战论文,但是感觉看的很慢而且很难抓住要点
很想了解其他人是怎么快速看完论文,抓住要点并且学习的。一般一篇论文アイラちゃん总会花上 3-5 天(全力)才能看完......
下午看的论文是 sigcomm'14 很经典的 CONGA,一篇针对数据中心的分布式拥塞感知与负载均衡方案。(只看完了动机和目的。。。 🐷)
部分的要点
CONGA 观察到了 ECMP 在负载均衡方面的缺陷:
- 爆发大流时受限于哈希随机分配,碰撞概率增大导致负载不均衡。
- 仅关注局部信息而未关注到潜在下游通路的拥塞影响。
导致了链路故障情况下即使有冗余也使得成功送达流量下降 40%。
并且,针对其他解决方案的不足:如中心化调度导致的数据中心场景下流量快速变化的反应不足,局部路由特性对全局掌握不佳,基于终端主机的传输层协议增加传输层复杂度并且无法控制绕开内核具有自身协议栈的高性能应用,提出了属于自己的方案:
- 分布式框架,允许在 RTT 尺度下进行拥塞反应。
- 全局拥塞信息控制,leaf-leaf 控制快速传输网络拥塞指标
- 独立于传输层的网络层部署,避免影响终端主机和引入复杂的传输层控制。
需要满足:高效性,传输层独立,不对称性稳定,可增量部署,可以针对 Leaf-spine 拓扑优化。

晚上要复习数学了~论文明天再继续看,CONGA 是怎么设计的。
图来自 X: @ sei_umehara

アイラちゃん 看不懂喵😭
窝是来看美图的喵 🫠
尽力做到每大更一次贴一张图 🥰
アイラちゃん 好的喵 🥰
2025 年 6 月 1 日 星期一 天气:中雨
上午:
https://xjtu.app/t/topic/14653/23
下午:
https://xjtu.app/t/topic/14653/25
晚上:
先结束了一元积分的基础复习。先把知识点和基础题都过一遍就好。
数学复习到了多元函数微分,最为头疼的还是多元函数连续/可导/可微/存在极限的关系,还是要记一下这张图 😵💫

祝各位晚安,好梦~ 🥰
X: @Tenkaichiho0

アイラちゃん lz 好自律🥹
长恨此身非我有 何时忘却营营
紫金港第一皮革<・)))><< 大一大二一点不自律 🥲现在只是为了抱佛脚,看看能不能继续上学 😭
其实我更想打 MC,每天 🐖,但是边缘人太折磨了,又不想太早出来工作,想读硕士后再工作
アイラちゃん 话说 LZ 有 paper 的 readlist 吗,还是组里相关的任务什么的
Zerick 是暑期打算在实验室实践(必修,可以走企业实践也可以在学校实验室实践),偏网络仿真方向(开发),目前是学长给了“负载均衡”的相关文献调研,所以读论文,后面还要上 ns3 开发 😇
アイラちゃん 每天 🐖
我也想做一只快乐的皮革兔🥹
长恨此身非我有 何时忘却营营
紫金港第一皮革<・)))><< 其实有好多想做的事
想自驾游从上海回家(海南海口),想学日语考过 N2 然后出国玩一下,想要自驾游从四川到西藏,有很多想做的事,如果有机会一定会好好玩一玩 😋
高考结束后的那个暑假几乎完全没有了,后面每个暑假都被小学期所占据,没有多少时间玩,有点可惜 🥲
悟已往之不谏,知来者之可追
アイラちゃん 很想了解其他人是怎么快速看完论文,抓住要点并且学习的。
+1,我现在非常容易陷入到实现里出不来,但是不看实现又 get 不到 paper 在干什么。
感觉还是读得太少了不知道学界现状,缺少 taste(x
Zerick 对的,可能是需要积累吧。现在总是有很多陌生的术语/词汇,所以阅读的时候磕磕绊绊,但是读多了积累多了应该就快一些了 ![]()
アイラちゃん 想自驾游从上海回家(海南海口),想学日语考过 N2 然后出国玩一下,想要自驾游从四川到西藏
好厉害啊🥹
希望 lz 有朝一日能实现这些目标吧
长恨此身非我有 何时忘却营营
アイラちゃん 同 😭驻波感觉目前不靠任何辅助阅读的手段就会读的很慢,或者晕乎乎的💦常常是看到一半就忍不住让 GPT 翻译了 + 总结要点
アイラちゃん在 zotero 里加装了 bionic 插件
https://github.com/windingwind/bionic-for-zotero

效果是这样的,会稍微有所提升阅读速度,浏览器アイラちゃん也会在阅读长 blog 的时候启用插件辅助阅读
一般来说长文阅读アイラちゃん很容易丢失上下文信息或者不专注(包括中文),阅读很慢,这样会稍微快一些
アイラちゃん 这样吗,有点意思🤔
(确实感觉怪提神的 ![]()
驻波回去也试试喵
今天的天气很舒服,所以上午偷懒了一个小时才起床 🥲
X:@Gameillust_AI

上午结束!说实话有些遗憾,因为刷 leetcode 解题的速度还是比较慢,需要进一步熟悉知识点 + 提升解题/写代码的速度。
每日一题是经典的贪心!
135. 分发糖果 (H)(2025.06.02)
C++
class Solution {
public:
int candy(vector<int>& ratings) {
// Two times iteration.
vector<int> ans;
int count = 1;
ans.emplace_back(count++);
for(int i = 1; i < ratings.size(); i++) {
if(ratings[i] > ratings[i-1]) {
ans.emplace_back(count++);
}
else {
count = 1;
ans.emplace_back(count++);
}
}
#ifdef DEBUG
cout << ans.size() << ' ' << ratings.size() << '\n';
for(int i = 0; i < ans.size(); i++) {
cout << ans[i] << ' ';
}
cout << '\n';
#endif
count = 1;
for(int i = ratings.size() - 1; i > 0; i--) {
if(ratings[i-1] > ratings[i]) {
ans[i-1] = max(ans[i-1], ++count);
}
else {
count = 1;
ans[i-1] = max(ans[i-1], count);
}
}
#ifdef DEBUG
cout << ans.size() << ' ' << ratings.size() << '\n';
for(int i = 0; i < ans.size(); i++) {
cout << ans[i] << ' ';
}
cout << '\n';
#endif
return reduce(ans.begin(), ans.end());
}
};
Go
func candy(ratings []int) int {
n := int(len(ratings))
ans := make([]int, n)
count := 1
ans[0] = count
count++
for i := 1; i < n; i++ {
if ratings[i-1] < ratings[i] {
ans[i] = count
count++
} else {
count = 1
ans[i] = count
count++
}
}
count = 1
for i := n - 1; i > 0; i-- {
if ratings[i-1] > ratings[i] {
count++
ans[i-1] = max(ans[i-1], count)
} else {
count = 1
}
}
var final int = 0
for i := 0; i < n; i++ {
final = final + ans[i]
}
return final
}
继续复习图论:这是图论中经典的拓扑排序,采用 Kahn 算法。
https://oiwiki.com/graph/topo/#kahn-算法
C++
好麻烦的题目
class Solution {
public:
bool isPrintable(vector<vector<int>>& targetGrid) {
// The tuple has color -> (up, down, left, right).
unordered_map<int, tuple<int,int,int,int>> color_mat;
// Find the tuple mat from the graph.
for(int i = 0; i < targetGrid.size(); i++) {
for(int j = 0; j < targetGrid[i].size(); j++) {
int color = targetGrid[i][j];
if(color_mat.find(color) == color_mat.end()) {
color_mat[color] = make_tuple(INT_MAX / 2, 0, INT_MAX / 2, 0);
}
const auto & [up, down, left, right] = color_mat[color];
color_mat[color] = make_tuple(min(up, i), max(down, i), min(left, j), max(right, j));
}
}
// Search the matrix and find the topology order.
unordered_map<int, unordered_set<int>> graph;
unordered_map<int, int> inDegree;
for(const auto & ele: color_mat) {
const int & color = ele.first;
const auto & [up, down, left, right] = ele.second;
graph[color] = unordered_set<int>();
if(inDegree.find(color) == inDegree.end()) {
inDegree[color] = 0;
}
for(int i = up; i <= down; i++) {
for(int j = left; j <= right; j++) {
if(targetGrid[i][j] != color && graph[color].find(targetGrid[i][j]) == graph[color].end()) {
graph[color].insert(targetGrid[i][j]);
inDegree[targetGrid[i][j]]++;
}
}
}
}
int n = graph.size();
queue<int> q;
int count = 0;
for(const auto & ele: inDegree) {
if(ele.second == 0) {
q.emplace(ele.first);
}
}
while(!q.empty()) {
int cur = q.front();
q.pop();
count++;
for(const auto & adj: graph[cur]) {
if(--inDegree[adj] == 0) {
q.emplace(adj);
}
}
}
#ifdef DEBUG
for(const auto & element: color_mat) {
const auto & [u,d,l,r] = color_mat[element.first];
cout << element.first << ":(" << u << ',' << d << ',' << l << ',' << r << ")\n";
}
for(const auto & element: graph) {
cout << element.first << " -> (";
for(const auto & adj: element.second) {
cout << adj << ',';
}
cout << '\n';
}
for(const auto & element: inDegree) {
cout << element.first << ": " << element.second << '\n';
}
cout << count << ' ' << n << '\n';
#endif
return count == n;
}
};
下午要和同学做星期四上午的 pre,以及交换星期二的数据挖掘推荐系统的展示 demo。看来今天下午又无法读论文了......没有意义的大作业真的害人不浅,强烈抨击金课! 😤 先去 🐷啦~
🐖

アイラちゃん 自律 🏃
i-BuProfen 再不跑就生锈了 🥲
现在又下雨了完蛋了 😇
アイラちゃん 好自律
对我来说 跑步一直是极度痛苦的事情😖
长恨此身非我有 何时忘却营营
アイラちゃん 既不想上学也不想上班 我也想每天 🐖
想到将来还要至少上 20 年班我就不行了😭
此人不语,只是一味地在门里生产废料。
post deleted by author 我也不想当社畜 😭
post deleted by author 为什么才 20 年
鳳 笑夢 三十五岁危机 ![]()
此人不语,只是一味地在门里生产废料。
2025 年 6 月 2 日 星期一 天气:小雨转阴
上午:
https://xjtu.app/t/topic/14653/43
下午和晚上:和同学完成星期四 ppt 的制作,以及星期二 demo 的制作。但是没想到我的 baseline 数据竟然不见了!平台的监控数据只保存 14 天,所以今晚要赶紧取得数据补充好我们的 PPT。PPT 上涉及到了模型、算法改动后与 baseline 的对比,虽然效果好像都没有比 baseline 好,甚至比 baseline 差,但还是要展示出来,分析出来效果不好的原因。但是同学训练的 reward 版本很好。
晚上一直在处理数据和 PPT,一点也不想搞了,好累口牙~~~
https://xjtu.app/t/topic/14653/44
希望能坚持自律~不然身体会垮掉的 😥
明天又要上课了,不想上课,不想工作 🥲 只想快乐地 🐷~
祝大家有美好的新的一周!晚安~
X: @ComikeMaster

坚持每日一题是我的 leetcode 账户名,所以就算今天上午 pre,我也要完成它!
(小声:其实做过了)
1298. 你能从盒子里获得的最大糖果数 (1825H)(2025.06.03)
C++
class Solution {
public:
int maxCandies(vector<int>& status, vector<int>& candies, vector<vector<int>>& keys, vector<vector<int>>& containedBoxes, vector<int>& initialBoxes) {
// 2 times bfs. First get all the boxes final status. Second get the candies.
queue<int> q;
for(const auto & init: initialBoxes) {
q.emplace(init);
}
while(!q.empty()) {
int cur = q.front();
q.pop();
if(status[cur] == 1) {
for(const auto & key: keys[cur]) {
status[key] = 1;
}
}
for(const auto & adj: containedBoxes[cur]) {
q.emplace(adj);
}
}
// Then get the boxes candies.
int ans = 0;
for(const auto & init: initialBoxes) {
q.emplace(init);
}
while(!q.empty()) {
int cur = q.front();
q.pop();
if(status[cur] == 1) {
ans += candies[cur];
}
for(const auto & adj: containedBoxes[cur]) {
q.emplace(adj);
}
}
return ans;
}
};
下午先战数据库作业,然后准备后天 pre 的材料 + 再看看做好的复习笔记准备后天下午的考试!
祝自己一切顺利!
X: @kasuga_iz

感觉好像什么都在坏掉
今天感觉心脏有点难受,一个月前买的 pad 的充电线坏了,Mac 的充电线也坏了,type-C aux 转接线也坏了,跑步的鞋也开裂了,今早书包也坏了一个口子出来(看错了,书包是好的 🤣)
只能重新买了吗,但是开销挺大的 🥲
アイラちゃん 那很坏了 🤣
🫳
战数据库事务处理 😤
晚上再补齐 OCC( ✅️ )和 MVCC ⭕️ 🐷
X:@haimiya_neno

事务处理与并发控制
事务基础与并发控制
事务
- 事务 (Transaction) 是什么?
- 是一组数据库运算的集合,可以抽象成一个的不可分的逻辑工作单元
ACID 特性
- 事务具有 ACID 特性
- Atomicity: 原子性,即不可分割。事务要么完全执行,要么完全不执行。
- Consistency: 事务必须保持数据库系统满足持续性,也就是满足数据库系统中的原先拥有的关系和条件。
- Isolation: 隔离性,每个事务都是独立运行,相当于仅仅在单独运行自己。
- Durability: 持续性。事务必须可以从错误中恢复。
并发控制
- 什么是并发控制?并发控制的目的是什么?
- 并发控制是数据库系统保证多个事务运算正确交叠的机制。目的是为了保证事务之间的隔离性,同时增加数据库处理速度,提高吞吐率。
保证正确的交叠:从序列化执行开始
为了简化调度方式,将数据库内的所有操作都看做仅有对特定资源的读取和写入操作。我们用 表示第 i 个事务读取数据 A, 表示第 i 个事务写入数据 A。
序列化调度与等价调度
- 没有任何交叠操作的调度 -> 序列化调度。即完成一个事务的所有操作才去执行下一个事务的操作。
- 等价调度是一组执行效果相同的调度的集合。
可以序列化的调度
- 具有交叠操作的调度等价于某些事务的序列化操作。
- 每个可序列化的调度都可以确保持续性的时候,我们的序列化调度是可持续的。
- 需要我们判断调度是否可序列化。
判断调度可序列化
矛盾操作
- 一对矛盾的操作将具有:
- 不同的事务面向同一份资源。
- 至少有一个操作是写操作。
- 这样我们有:(R1W2 不可重复读),(W1R2 脏页读),(W1W2 更新丢失) 均为矛盾操作。(目前不考虑假性读取和写入偏移)
可序列化的不同层级
-
冲突可序列 (confilict serializability)
- 两个调度是冲突等价的,当且仅当
- 拥有相同事务且事物内部操作相同。
- 两个调度中冲突操作的顺序是相同的。也就是说如果调度一中是 (R1W2),那么调度二也必须保证 R1 在 W2 之前。
- 调度 是冲突可序列的,当它
- 在冲突操作上的顺序与某些序列化调度相同。也就是说,你可以将他转换成序列化调度。
- 两个调度是冲突等价的,当且仅当
-
视图可序列 (view serializability)
- 两个调度是视图等价的当它们
- 事务 1 在调度 1 中读取的初始值和在调度 2 中读取的初始值相同。
- 事务 1 在调度 1 中读取到事务 i 写入的值,则在调度 2 中也应该读取到事务 i 写入的值。
- 所有的最终结果都必须由一个事务来完成。
- 两个调度是视图等价的当它们
-
很显然冲突可序列化是比视图可序列化更严格 的。
前序图
- 判断是否冲突可序列化的简单的方法。
- 每个事务作为一个节点。每个冲突操作对作为一条边。
- 当前序图是有向无环图时,恭喜你它是冲突可序列化的。
并发控制方法
为了保证得到正确的交叠操作调度,我们需要一些并发控制方法。
锁的类型(其实是读写锁换皮)
- 共享锁:用于读操作的共享锁。
- 排它锁:用于写操作的排它锁。
| 可执行判断 | 共享锁 | 排它锁 |
|---|---|---|
| 共享锁 | ✅️ | ❌️ |
| 排它锁 | ❌️ | ❌️ |
简单的排它锁和共享锁无法保证可序列性。
二阶段锁
-
阶段一:获得锁
- 每个事务获取他所需要的锁。
- 可能被拒绝或允许,但是在该阶段不允许有释放锁的行为。
-
阶段二:释放锁
- 每个事务释放它所需要的锁。
- 不允许任何事务获得锁。
- 严格的二阶段锁:在所有事务结束后才能统一释放锁。可以解决脏页读问题。
- 二阶段锁可能导致死锁。通过检测和预防来避免死锁 (银行家算法等...)
- 这里不探索如何解决死锁。
-
一个调度是严格的当一个事务写入一份数据后,其他事务不能读取或覆盖这份数据,直到该事务终结。
-
可以看出严格程度:严格序列化 > 严格二阶段锁 > 冲突可序列化 > 视图可序列化
时间戳排序控制 (T/O)
- 采用时间戳来决定序列化调度中事务执行的顺序。当 TS(T1)<TS(T2) 的时候,执行顺序必须为 T1 -> T2.
- 基础时间戳
- 事务自身将拥有时间戳;TS( )
- 每个数据对象也将有自己的时间戳。
- 数据 X 的读时间戳:R(X)
- 数据 X 的写时间戳:W(X)
基础时间戳控制
-
读操作
- 当 TS(T) < W(X) 的时候,回滚并重新开始,赋予新的 TS(T).
- 否则持续执行并且 .
- 允许拷贝一份 X 来保证重复读取。
-
写操作
- 当 TS(T) < W(X) 或者 TS(T) < R(X) 的时候,回滚并重新开始,赋予新的 TS(T).
- 否则持续执行并且
-
基础的时间戳操作保证了冲突可序列性质。
托马斯写 + 时间戳控制
-
写操作处有所不同。
- 当 TS(T) < R(X) 的时候,回滚。
- 当 TS(T) < W(X) 的时候,忽略写操作,继续执行(因为很快时间戳后面的事务的写操作将覆盖本次的写操作)。
- 否则持续执行并且
-
很明显仅保证视图可序列性。
OCC(乐观并发控制)
- 时间戳协议。
- DBMS 为每一个事务创建了一个私有的工作空间。
- 每个被读取的对象将被复制到工作空间中,对对象的编辑也将加入到工作空间中。
- 当事务提交时,DBMS 将会对比工作空间写集合,每个事务的写空间相同时,装载到全局数据库中。
三阶段
- Read,读取。跟踪每个事务的读、写集合,储存他们的写入对象到私有的工作空间中。DBMS 将会复制一个事务中所有需要的元组到共享数据库中保证可重复读。
- Validation,验证。给每一个事务独有的时间戳,检查他们是否于其他对象相互冲突。
- 当事务唤起提交时,进入验证部分。
- 前向验证:检查正在提交中的事务读/写集合是否与活动中的未提交事务相互重叠。
- 检查时间戳。当提交事务时间戳小于其他活动事务时,需要满足三个条件:
- (1) 其他事务读阶段位于当前事务写阶段完成之后。R2(A)>W1(A)
- (2) 其他事务写阶段在当前事务写阶段完成之后。W2(A)>W1(A), 并且 当前事务没有修改任何其他活动事务要读取的对象。
- (3) 其他事务读阶段在当前事务读阶段完成之后。R2(A)>R1(A), 并且当前事务不修改任何T2 将会读取或写入的对象。
- 反向验证:检查正在提交中的事务读/写集合是否与活动中的已提交事务相互重叠。仍然遵循三条原则。
- 检查时间戳。当提交事务时间戳小于其他活动事务时,需要满足三个条件:
- Write,写。当验证成功时,对所有已经编辑过的对象设置写时间戳,装载他们进入全局数据空间。否则回滚,中断事务。
2025 年 6 月 3 日 星期二 天气:多云
上午:
Demo,以及
https://xjtu.app/t/topic/14653/53
下午和晚上:
https://xjtu.app/t/topic/14653/56
不过没太看明白 MVCC,明天补上来 Note,再 copy 到 blog 上~
星期五又要组会,要炸了,アイラちゃん还没看完 reading list,明天一整天要加油看完 🥲
祝大家好梦~晚安 nya
X:@OuToTmeM

忙晕了,提前更一下日记楼~
2025 年 6 月 4 日 星期三 天气:多云
上午修改明天准备汇报的 ppt,评测结果出来了,强化学习对抗实在是太折磨人了,Level3 的胜率才 25%,不过 Level2 和 Level1 我们的胜率都是 100%。还是可以的吧。
其实做了很多的尝试,更换模型和算法,但是很显然这是不正确的。对抗性最重要的就是 reward 设计,前面的部分应该是在 reward 设计完了后再进行的工作。战略上的失误使得我们还是失去了一些优势。果然盲目的勤奋是没有办法掩盖战略上的懒惰的。这一点需要深思。
下午抽时间 leetcode 保持手感。
C++
class Solution {
public:
string lastSubstring(string s) {
int i = 0, j = 1, n = s.size();
while (j < n) {
int k = 0;
while (j + k < n && s[i + k] == s[j + k]) {
k++;
}
if (j + k < n && s[i + k] < s[j + k]) {
int t = i;
i = j;
j = max(j + 1, t + k + 1);
} else {
j = j + k + 1;
}
}
return s.substr(i, n - i);
}
string answerString(string word, int numFriends) {
if(numFriends == 1) {
return word;
}
string last = lastSubstring(word);
int n = word.size(), m = last.size();
return last.substr(0, min(m, n - numFriends + 1));
}
};
C++
#define DEBUG
#undef DEBUG
class Solution {
public:
string alienOrder(vector<string>& words) {
unordered_map<char, unordered_set<char>> graph;
unordered_map<char, int> inDegree;
bool flag = false;
auto add_edge = [&](const string & l, const string & r) -> void {
int i = 0;
for(i = 0; i < min(l.length(), r.length()); i++) {
if(graph.find(l[i]) == graph.end()) {
graph[l[i]] = unordered_set<char>();
}
if(inDegree.find(l[i]) == inDegree.end()) {
inDegree[l[i]] = 0;
}
if(l[i] != r[i] && graph[l[i]].find(r[i]) == graph[l[i]].end()) {
flag = true;
graph[l[i]].insert(r[i]);
inDegree[r[i]]++;
break;
}
else if(l[i] != r[i]) {
flag = true;
break;
}
}
if(!flag && l.length() > r.length()) {
return;
}
flag = true;
int temp = i;
for(; i < l.length(); i++) {
if(graph.find(l[i]) == graph.end()) {
graph[l[i]] = unordered_set<char>();
}
if(inDegree.find(l[i]) == inDegree.end()) {
inDegree[l[i]] = 0;
}
}
i = temp;
for(; i < r.length(); i++) {
if(graph.find(r[i]) == graph.end()) {
graph[r[i]] = unordered_set<char>();
}
if(inDegree.find(r[i]) == inDegree.end()) {
inDegree[r[i]] = 0;
}
}
};
// Step 1: Add edges.
if(words.size() == 1) {
flag = true;
for(int i = 0; i < words[0].length(); i++) {
if(graph.find(words[0][i]) == graph.end()) {
graph[words[0][i]] = unordered_set<char>();
}
if(inDegree.find(words[0][i]) == inDegree.end()) {
inDegree[words[0][i]] = 0;
}
}
}
else {
for(int i = 0; i < words.size(); i++) {
for(int j = i + 1; j < words.size(); j++) {
add_edge(words[i], words[j]);
}
}
}
#ifdef DEBUG
for(auto & elem: graph) {
cout << elem.first << ": ";
for(const auto & adj: elem.second) {
cout << adj << ' ';
}
cout << '\n';
}
for(auto & elem: inDegree) {
cout << elem.first << ": " << elem.second << "\n";
}
string flag_str = (flag == true) ? "true" : "false";
cout << flag_str << '\n';
#endif
// Step 2: TopoSort.
queue<char> q;
string ans;
for(const auto & ch: inDegree) {
if(ch.second == 0) {
q.emplace(ch.first);
}
}
while(!q.empty()) {
char ch = q.front();
ans.push_back(ch);
q.pop();
for(const auto & adj: graph[ch]) {
if(--inDegree[adj] == 0) {
q.emplace(adj);
}
}
}
return ans.length() == graph.size() && flag ? ans : "";
}
};
C++
基于基环树的思想。
class Solution {
public:
int maximumInvitations(vector<int>& favorite) {
int n = favorite.size();
vector<vector<int>> reverse_graph(n);
queue<int> q;
vector<int> inDegree(n, 0);
for(int i = 0; i < n; i++) {
inDegree[favorite[i]]++;
}
for(int i = 0; i < n; i++) {
if(inDegree[i] == 0) {
q.emplace(i);
}
}
while(!q.empty()) {
int cur = q.front();
q.pop();
// Build reverse_graph;
reverse_graph[favorite[cur]].emplace_back(cur);
if(--inDegree[favorite[cur]] == 0) {
q.emplace(favorite[cur]);
}
}
// Dfs reverse graph find the shortest edge.
auto dfs = [&](this auto && dfs, int from) -> int {
int max_depth = 1;
for(const auto & adj: reverse_graph[from]) {
max_depth = max(max_depth, dfs(adj) + 1);
}
return max_depth;
};
// Find the cycle.
int ring = 0, chain = 0;
for(int i = 0; i < n; i++) {
if(inDegree[i] == 0) {
continue;
}
inDegree[i] = 0;
int tmp_ring = 1;
for(int adj = favorite[i]; adj != i; adj = favorite[adj]) {
inDegree[adj] = 0; // mark as visited.
tmp_ring++;
}
if(tmp_ring == 2) {
chain = chain + dfs(i) + dfs(favorite[i]);
} else {
ring = max(ring, tmp_ring);
}
}
return max(chain, ring);
}
};
然后焦虑/抑郁状态出现了,突然一下子什么都不想干,只能停下手中的学习任务去外面走一走 🥲
拍照的地方在兰香湖附近,是アイラちゃん心情不好的时候最常去的地方。只要在安静的地方发上半个小时的呆,好像什么都会变好的。有时候止不住地想,是不是我选择了错误的道路,选择了错误的人生,还是什么时候做了错误的事情呢,以至于现在进退两难,也不知道未来在哪里,为了尝试保研也没有认真的去找工作。如果,如果考研和保研都失败了,没有实习经验的アイラちゃん又应该怎样才能找到理想的工作呢,如果不找本专业的工作我又会什么呢。现在的アイラちゃん还不知道答案是什么,未来在何处。



今天晚上就是准备明天下午的考试了,希望能够一切顺利吧,明天上午的 pre,明天下午的考试。星期五的组会明天考完试再准备吧。
祝大家今晚好梦~
X: @ji10me

アイラちゃん 现在的アイラちゃん还不知道答案是什么,未来在何处。
我也是😭
此人不语,只是一味地在门里生产废料。
アイラちゃん 如果,如果考研和保研都失败了,没有实习经验的アイラちゃん又应该怎样才能找到理想的工作呢,如果不找本专业的工作我又会什么呢。
答案是并不会怎么样 😁 你想太多了
IO 确实,这种东西太看时代和机遇了。坏时代诺奖得主也要变卖奖牌维持生计,国内院士扫大街;好时代没读过书也能有机会成为顶流网红,带货千万。
2025 年 6 月 5 日 星期四 天气:多云
心情很不好呀。
同一时期投简历的同学今天都收到了面试邀请然后进行了面试,但是我连面试通知都没有收到。(是学校统一安排的专业暑期实习)
虽然打算在学校内实验室进行实习,但是知道自己甚至连面试条件都不准入还是有些伤心的。可能自己的水平确实不够吧,自己平庸的成绩和平庸的表现也确实很难入别人的法眼。接下来还是应该默默地继续努力准备考研,在收留我的实验室组里做一些工作,多学习一些吧。
实力才是硬道理。没有成绩,没有项目傍身的我属实单薄无力。我的喜欢和热爱可能不会成为我最后选择的道路吧,有可能我会在未来放弃计算机,放弃 coding 吧,当真正没有办法的时候。
不过目前アイラちゃん不会那么轻易放弃的。至少让我丑陋地挣扎一下吧,为了一点微不足道的可能。
今天上午的题目是经典的并查集。只需要按照字典序进行 merge 即可。
C++
// #define debug
class Union {
public:
vector<int> parent;
int n;
// The Costruction function.
Union(int n):n(n),parent(vector<int>(n)) {
iota(parent.begin(), parent.end(), 0);
}
// Path compression. Find parent until the same.
int find(int id) {
if(parent[id] != id) {
parent[id] = find(parent[id]);
}
return parent[id];
}
// Merge by size. You can also make it by rank, for modified as size[pa_i] += 1;
void merge(int id1, char id2) {
// Find parent.
int pa1 = find(id1);
int pa2 = find(id2);
if(pa1 == pa2) {
return;
}
else if(pa1 < pa2) {
parent[pa2] = pa1;
}
else {
parent[pa1] = pa2;
}
}
bool judge(int id1, int id2) {
return find(id1) != find(id2);
}
};
class Solution {
public:
string smallestEquivalentString(string s1, string s2, string baseStr) {
Union u(26);
for(int i = 0; i < s1.length(); i++) {
u.merge(s1[i] - 'a', s2[i] - 'a');
}
#ifdef debug
for(auto & element: u.parent) {
cout << element.first << ' ' << element.second << '\n';
}
#endif
string ans;
for(int i = 0; i < baseStr.length(); i++) {
ans.push_back(u.find(baseStr[i] - 'a') + 'a');
}
return ans;
}
};
上午进行了 RL 的 pre,预计明天把报告干出来。
下午考完了试,也意味着期末周已经结束了。
晚上就是不停地赶报告,目前已经写完了更换模型部分 (MLP+LSTM) 更换成 transformer encoder-decoder,transformer+LSTM 部分,以及 dual PPO 和 PPG 的一部分。明天再把剩下的实验结果补充在报告中。只是有些可惜 SAC 的探索失败了,一个分布式框架我不太了解如何将数据序列化传输给训练主机,再将数据反序列化传递回 env,这就导致了我无法完成 off-policy 操作。
今天心情不太好,就不放图了,祝大家未来一帆风顺,今晚做个好梦,晚安。
アイラちゃん 好想大哭一场,但是已经很晚了,会影响到别人休息。大学三年我到底做到了什么呢?学会了什么呢?这三年我是尽力完成了,还是得过且过呢?如果是得过且过,为什么会如此疲惫不堪?如果不是,结果为何不堪入目呢?
无法寻找到答案,也无从知晓答案。不会有人告诉我为什么,因为过程并不重要;成绩❌和暑期实习❌的结果已经说明了一切。
有点累,不想码字了,先睡吧,如果能睡着的话。有可能的话,我好想重新开始一切,平平凡凡地走过人生。或者是有可能的话,重来一次太累,不如一劳永逸地结束吧。
讨厌现在的自己
讨厌现在的生活
早上起床头有些疼,布洛芬又救了我一命。感谢止疼药 💊
然后补完了报告中属于自己的部分。剩下的格式调整和补充等到组内的其他小伙伴完成后再进行修改。这个学期也即将随着夏天的到来而落下帷幕。
然后还是一样先做每日一题。Coding 需要保持手感,否则很快就萎缩了 😵💫
今天是贪心 + 栈。一开始对于贪心的设计不足导致出错,后来发现不能按照单调的方式去想,贪心应该贪心到剩余字符中最小的字符才可以。感觉好像有些晕晕的~
C++
class Solution {
public:
string robotWithString(string s) {
int n = s.length();
vector<char> min_str(n+1);
min_str[n] = 'z';
for(int i = n - 1; i >= 0; i--) {
min_str[i] = min(min_str[i+1], s[i]);
}
stack<char> st;
string ans;
for(int i = 0; i < n; i++) {
st.push(s[i]);
while(!st.empty() && st.top() <= min_str[i+1]) {
ans.push_back(st.top());
st.pop();
}
}
return ans;
}
};
X: @ArameDraw

IO 


今天忙的事情太多啦,明天早上更 🥺
IO 为啥会有人信和传播这些不切实际的胡说八道,为了泄愤罔顾事实?
阿根廷生存压力可比国内大多了,那些踢足球的酒囊饭袋工资比欧洲都高
纯粹是对足球本身没啥兴趣,能捞到钱就躺
2025 年 6 月 6 日 星期五 天气:多云
昨天太乱了把事情都忘了~
上午:https://xjtu.app/t/topic/14653/65
下午上完最后一节数据库课程,大学的所有必修课程也就全部结束了。暑期的实践也只有实验室的项目,其他意向的校外实习全部挂掉了~
随后校内的夏令营开了,就跑来跑去准备材料,但是应该不会报上的吧~其他大学的开放交流日也杳无音讯,一些学院需要的推荐信啥的也什么都没有呢,所以也不需要抱太大的希望。然后晚上 23 点的时候小组同学说报告的格式崩掉了。于是又去想着怎么修格式去了。
目前的计划还是一样按照 https://xjtu.app/t/topic/14653/3 来慢慢推进。一直努力到最后的时刻,之后的路只能且走且看,珍惜自己本科的最后一段时光吧。
愿我们都能获得自己想要的未来。
X: @ArameDraw

fight on なのです!
跑之前没有清鞋里的沙子,痛~

アイラちゃん 随后校内的夏令营开了,就跑来跑去准备材料
我今天刚看到 想着报不上就准备放弃了 把目前在联系的其他学校老师的考核认真做一做
好几天没看 lz 的日记了,感觉我日记没有这么 e 的原因只是单纯的因为土塬有认识我的校友所以不是很愿意彻底在这里解刨自己(笑
总之觉得 lz 已经很优秀了,也很感谢 leetcode 题单的分享
Zerick lz 也是,一边准备夏令营一边准备考研~
一起加油哦,我一直相信大老师说过的话:
努力不会背叛自己,梦想才会。
尽力做好所有的准备后,结果顺其自然。尽人事,听天命就是这个道理。烦恼和伤心,找一个地方记录下来,也算是一种倾泻的方式。
一步步向前走就好了 ![]()
今天可以好好 🐖
顺便奖励自己结束了大三学年

アイラちゃん 盲猜四餐 🐖
神秘小维 等有钱了再去外边好好 🐖 😤
2025 年 6 月 7 日 星期六 天气:小雨
今天考完了语文和数学,语文作文根本不会写,数学大题没做完,没有大学上了 QAQ
上午学习了相关跳表的数据结构,并且完成了基本的跳表操作,以及在整个表层面加入读写锁。对于 C++,我们在表结构内使用 std::shared_mutex 定义读写锁。采用 std::unique_lock 可以完成排他锁加锁工作,也就是写锁。写锁不允许除了持锁线程之外的锁进入到数据结构区域。对于读取操作,我们采用 std::shared_lock 加锁,也就是共享锁。共享锁允许多个仅进行读取操作的线程读入。一般来说是这样的:
简单实例
template<typename T>
class DataStructure {
public:
// Data Definition start
// ********
// Data Definition end
std::shared_mutex rwlock;
template<typename T>
T read() {
std::shared_lock rlock(rwlock); // Read operations with shared_lock;
// Read Operations;
}
template<typename T>
void write() {
std::unique_lock wlock(rwlock); // Write operations with exclusive_lock.
// Write operations;
}
};
对于多线程和 C++ 锁的 RAII 机制,以及原子操作和 CAS 方法还需要进一步地学习和实践。跳表的相关总结也需要在 Jun 8, 2025 (Asia/Shanghai) 尝试完成。
下午就是刷 leetcode。
3170. 删除星号以后字典序最小的字符串 (2025 年 6 月 7 日) (1772M)
这道题目的本质是贪心算法。对于贪心的设计不充分让主包感觉到了非常吃力,后面在图论结束后需要重点进攻 DP 和贪心。(80w vs 60w, 优势在我!)
并且通过这一题还尝试了 ranges 相关函数。
C++
#include<ranges>
class Solution {
public:
string clearStars(string s) {
vector<stack<int>> indices(26, stack<int>());
int count = 0;
for(int i = 0; i < s.length(); i++) {
if(s[i] == '*') {
for(int i = 0; i < 26; i++) {
if(!indices[i].empty()) {
s[indices[i].top()] = '*';
indices[i].pop();
break;
}
}
} else indices[s[i] - 'a'].push(i);
}
return s | ranges::views::filter([](char i) {return i != '*';})
| ranges::to<std::string>();
}
};
接下来就是图论部分:内向基环树。这类数据结构一般出现在每个节点均只有单个出边的有向无环图中,这样每个连通块有且仅有一个环,使得求取最长环成为可能。一般通过拓扑排序去除非环节点后进行。
典型的内向基环树问题。
C++
class Solution {
public:
int longestCycle(vector<int>& edges) {
// TopoSort to modify the graph.
int n = edges.size();
vector<int> inDegree(n, 0);
for(int i = 0; i < n; i++) {
if(edges[i] != -1) inDegree[edges[i]]++;
}
queue<int> q;
for(int i = 0; i < n; i++) {
if(inDegree[i] == 0) {
q.emplace(i);
}
}
while(!q.empty()) {
int cur = q.front();
q.pop();
int adj = edges[cur];
edges[cur] = -1;
if(adj != -1 && --inDegree[adj] == 0) {
q.emplace(adj);
}
}
int ans = -1;
auto dfs = [&](this auto && dfs, int from) -> int {
int nxt = edges[from];
if(nxt == -1) return 0;
edges[from] = -1;
return dfs(nxt) + 1;
};
for(int i = 0; i < n; i++) {
ans = max(ans, dfs(i));
}
return ans == 0 ? -1 : ans;
}
};
与其相反的,另一条最短环问题。对于最短环问题,我们需要逐个(假性)去除边,随后从该边的一个节点开始,进行 Dijkstra 或 floyd 最短路计算出该节点到另一个节点的最短距离,最后的最小环即为 。有向图则以出边为起点进行。具体可以查看:
https://oiwiki.com/graph/min-cycle/
C++
class Solution {
public:
int findShortestCycle(int n, vector<vector<int>>& edges) {
// Build graph.
vector<vector<int>> graph(n);
for(const auto & edge: edges) {
int u = edge[0], v = edge[1];
graph[u].emplace_back(v);
graph[v].emplace_back(u);
}
int * distance = new int [n];
// Dijkstra with delete the edge. For indirect graph, pick one side, run dijkstra.
// Directed should strictly follow start and end point.
auto bfs = [&](int u, int v) -> void {
queue<int> q;
q.emplace(u);
distance[u] = 0;
while(!q.empty()) {
int cur = q.front();
q.pop();
for(const auto & adj: graph[cur]) {
// False delete.
if(cur == u && adj == v) {
continue;
}
// Updated.
else if(distance[adj] < 0x7f7f7f7f) {
continue;
}
else if(distance[adj] > distance[cur] + 1) {
distance[adj] = distance[cur] + 1;
q.emplace(adj);
}
}
}
};
int ans = INT_MAX / 2;
for(const auto & edge: edges) {
memset(distance, 0x7f, sizeof(int) * n);
int u = edge[0], v = edge[1];
bfs(u, v);
ans = min(ans, distance[v] + 1);
}
return ans == INT_MAX / 2 ? -1 : ans;
}
};
最后遇到的 冗余连接 I 和 冗余连接 II 放到 Jun 8, 2025 (Asia/Shanghai) 在进行记录,都涉及到了并查集问题。
随后就是 running+ 🐖
http://xjtu.app/t/topic/14653/70
http://xjtu.app/t/topic/14653/73
晚上被讲解抗日战争的视频硬控了,强力推荐,讲的非常详细,于是偏离主力工作摸鱼~
在此向革命前辈和先烈们致敬,永垂不朽。
https://www.bilibili.com/video/BV1E6TTz9Eqy
今晚就是这样了~祝大家晚安好梦,明天高考继续旗开得胜!
アイラちゃん 有一次面试让手撕读写锁给我干碎了
アイラちゃん
auto dfs = [&](this auto && dfs, int from) -> int {
int nxt = edges[from];
if(nxt == -1) return 0;
edges[from] = -1;
return dfs(nxt) + 1;
};
居然是 cpp23
Zerick 拥抱新标准 🤗
手撕读写锁那很坏了,直接用 C++17 😤
🫨op 的刷题和学习效率都好高
