lc494_目标和 2024黄仁勋加州理工毕业演讲 使用 Go 打造百亿级文件系统的实践之旅 Rocksdb快照,checkpoint,备份区分
Algorithm
lc494_目标和
思路:
先考虑暴力解法,枚举所有的正负数排列,因为长度是最大20,所以是 2^20, 1e6, 可以暴力枚举。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sz = nums.size();
int tmp = 0;
int ans = 0;
for (int i = 0; i < (1 << sz); i++) {
// 当前排列下的临时数值
tmp = 0;
for (int j = 0; j < sz; j++) {
// bit位为0是负数,为1是正数
tmp += i & (1 << j) ? nums[j] : -nums[j];
}
if (tmp == target) {
ans++;
}
}
return ans;
}
};
|
以上还是有 2e7 的复杂度,提交 TLE 了:
64 / 140 个通过的测试用例
没想出来,看了一下题解,发现题解的递归回溯竟然可以过???
就因为每轮数值在递归中操作的?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Solution {
public:
int count = 0;
int findTargetSumWays(vector<int>& nums, int target) {
backtrack(nums, target, 0, 0);
return count;
}
void backtrack(vector<int>& nums, int target, int index, int sum) {
if (index == nums.size()) {
if (sum == target) {
count++;
}
} else {
backtrack(nums, target, index + 1, sum + nums[index]);
backtrack(nums, target, index + 1, sum - nums[index]);
}
}
};
// 链接:https://leetcode.cn/problems/target-sum/solutions/816361/mu-biao-he-by-leetcode-solution-o0cp/
|
确实差距就是 O(2^n * n) 的 O(n), 在这种情况下还是用递归回溯。
更高效的解法是 dp 的方式:
巧妙把正负数转换成凑一个数的dp方式,比较难想到,学习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int& num : nums) {
sum += num;
}
int diff = sum - target;
if (diff < 0 || diff % 2 != 0) {
return 0;
}
int neg = diff / 2;
vector<int> dp(neg + 1);
dp[0] = 1;
for (int& num : nums) {
for (int j = neg; j >= num; j--) {
dp[j] += dp[j - num];
}
}
return dp[neg];
}
};
// 链接:https://leetcode.cn/problems/target-sum/solutions/816361/mu-biao-he-by-leetcode-solution-o0cp/
|
Review
黄仁勋加州理工演讲
没开中文字幕,也能听懂看懂,舒服。
老黄祝贺大家毕业,还讲到要祝贺那些帮助你们走到这个里程碑的家人和支持者们。视角很客观,并没有完全那种个人英雄主义。
当然老黄也是去加州理工招聘优秀大学生,哈哈,毫不避讳得说,挺好。
做优先级最高的事情,用一辈子去做,这样就有充足的时间做。–长期主义。
I hope you find a craft. 找到自己的命门,然后奉献一生做高优的事情,这样就有大把的时间做到极致。
Tips
极限挑战:使用 Go 打造百亿级文件系统的实践之旅
企业版不是用的tikv,而是自研元数据引擎,学习其中的思路,这里的知识就是金钱。
JuiceFS 企业版追求极致性能,因此采用的是第一种全内存方案,并通过不断的优化来减小文件元数据的内存占用。全内存模式通常会使用实时落盘的事务日志来保证数据的可靠性,JuiceFS 还使用了 Raft 共识算法来实现元数据的多机复制和自动故障切换。
这里感觉它的单线程无锁,其实和 raft 日志做任务分发差不多..
JuiceFS 采用了一种不同的方法,即类似于 Redis 的无锁模式。在这种模式下,所有核心数据结构的相关操作都在单个线程中执行。这种单线程方法不仅保证了每个操作的原子性(避免了操作被其他线程打断的问题),还减少了线程间的上下文切换和资源竞争,从而提高了系统的整体效率。同时,它大大降低了系统复杂度,提升了稳定性和可维护性。得益于全内存的元数据存储模式,请求都可以被非常高效地处理,CPU 不容易成为瓶颈。
因为维护了许多内存,所以自我用指针管理GC,防止Golang自带的GC的中断时间过长:
可见这些结构体都非常小,但是数量会非常庞大。Go 的 GC 不支持分代,也就是说如果将它们都交由 GC 来管理,就需要在每次进行内存回收时都将它们扫描一遍,并且标记所有被引用的对象。这个过程会非常慢,不仅使得内存无法及时回收,还可能消耗过多的 CPU 资源。
其中把申请的内存指针放在了一个大的kv的map里面,这样利用gc扫描的时候不管这个map多大都不会深入扫描map内部存储
的特性,极大减小golang GC的压力。
最终再通过压缩空闲数据,以及优化数据结构的方式,大大提高了元数据的内存利用率。
Share
Rocksdb快照,checkpoint,备份区分
- Snapshot: 只快照一个版本。比如在一次 Compaction 中,先快照一个版本,然后操作完就没了。A snapshot cannot outlive the DB session that created it.
- Checkpoint: 同文件系统同磁盘,会用硬链接复制。可以用于数据库分片。
- Backup: 类似于深拷贝,主要用于一次拷贝,多次复制。一般用于云备份多处分发。
参考: [Help ] What is the difference between backup and checkpoint ? which one will be recommended if I want to do backup restore operation