Algorithm
本周选择的算法题是:Maximize Score After N Operations。
impl Solution {
pub fn max_score(nums: Vec<i32>) -> i32 {
let mut dp = vec![-1; 1 << nums.len()];
Self::dfs(&nums, 0, &mut dp)
}
fn dfs(nums: &Vec<i32>, mask: usize, dp: &mut Vec<i32>) -> i32 {
if dp[mask] != -1 { return dp[mask] }
let mut k = nums.len();
for i in 0 .. nums.len() {
if mask & 1 << i != 0 { k -= 1; }
}
k >>= 1;
if k == 0 { return 0 }
dp[mask] = 0;
for i in 0 .. nums.len() {
for j in i + 1 .. nums.len() {
if mask & 1 << i != 0 || mask & 1 << j != 0 { continue }
let mask_new = mask | 1 << i | 1 << j;
dp[mask] = dp[mask].max(k as i32 * Self::gcd(nums[i], nums[j]) + Self::dfs(nums, mask_new, dp));
}
}
dp[mask]
}
fn gcd(a: i32, b: i32) -> i32 {
if a < b { return Self::gcd(b, a); }
if a % b == 0 { return b }
Self::gcd(b, a % b)
}
}
Review
Automate Your Busywork: Do Less, Achieve More, and Save Your Brain for the Big Stuff
从这篇文章中能看到很多感同身受的观点:
整天忙碌不是因为工作太多,而是工作方式有问题
- 人工智能不会取代人类,但使用人工智能的人会
- 我们最好的工作应该是计算机无法完成的工作
- 工作让你成为人,而不是生产力机器
作者对 “什么是 workflow” 也解释的非常清楚,“早晨去健身房” 只是一个行为,这个行为背后必须要做好计划,比如准备衣服、安排日程以准时到达那里,然后再准时到达办公室,这是一个为健身房做准备的完整工作流程。
我们忙碌、todo 事项太多,有可能是没有看清楚我们的 workflow 到底是什么。
Tip
两个新的函数: 深入了解 CSS 中的 :where() 和 :is() 函数。
Share
什么是容器
从架构角度,可以延伸出三种类型的容器:
- 应用容器
- 业务容器
- 运行容器
容器架构的完整形态应由这三部分组成。
应用容器
管理应用的生命周期,抹平应用间的差异。对应用容器来说,它们共享的是一整套基础设施,比如系统资源、DevOps、工程架构、共享组件以及配置,抹平开发环境、部署环境、接口环境等差异,并提供统一的 Sidecar 和应用级生命周期管理等。把一个新应用放入容器后,该应用初始状态下就已经具备了完整的应用生态,集成了埋点、日志等通用框架,以及稳定性解决方案等。
业务容器
业务(模块)级的生命周期管理,隔离、抹平业务间的差异。对业务容器来说,他们共享的是一套运行环境,拿复杂的美团举例,美团有独立的美团外卖产品,还有美团优选、美团买菜等产品,这些产品的背后是一条条独立的业务线,这些业务线既可以在独立的应用内闭环,也可以聚合为美团这个超级应用,既是原子化的业务组件,同时组件即应用。为了实现这一点,必须抽象出业务容器的概念,当打开美团外卖时,或者打开美团的外卖模块时,执行的业务逻辑没有任何区别(对业务层来说),并且退出功能模块或者退出整个产品,在资源回收等方面也没有差异,这些差异被业务容器抹平了,对业务来说,只需要关心业务的生命周期,并在对应的时机执行业务逻辑即可。
运行容器
运行容器是为特定场景提供的运行时环境,抹平运行时之间的差异,比如 WebView 和 FlutterView 的运行时差异,还有 FFI 要抹平的 Java、C++ 互调用差异等,它是面向具体技术生态提供的解决方案。对技术生态来说,它要把不变的部分和变化的部分隔离出来,比如不变的框架、标准层,而容易变化的是运行环境,拿 ArkUI 来说,它针对嵌入式场景提供了 JerryScript,为中等性能设备提供了 QuickJS,为高性能场景提供了 V8 引擎,这是一种基于场景的解决方案,识别到场景之间的差异性并提供最优解的同时,对业务隐藏了引擎(运行时)的差异。