|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
×
作者:微信文章
刚看到个贴子,说AI时代基础代码都被机器写了,程序员怕被替代。网友还回了句“车到山前必有路”,嗯…听着是安慰,但不完全能当策略哈。
我作为前端看的话,这事吧,焦虑能理解,但躺平真没用。AI写的更多是“能跑”的代码,不是“能落地”的产品。前端的业务理解、交互细节、性能权衡、与设计和后端的沟通,这些AI都替不了。网友的意思我也明白——别太早吓自己,但我觉得关键还是得主动转。像老项目的维护、需求拆解、联调踩坑,这些没人愿意干的活,恰恰是价值所在。
换个角度想,AI更像是给我们凿土的电镐,有工具不学用,才真会被替代。能写代码的人很多,能把需求落地的人永远稀缺。
总的来说,别怕技术变,怕的是自己停。顺势提升,才能越走越稳。
【备注:文末可领最新资料】
今日算法题:生命游戏
要说最近几年刷题界有什么老网红一直常青,那“生命游戏”绝对能算一个。你说它是算法题吧,确实考察状态转换和数组操作;但你要说它不浪漫,那也不太对——毕竟人家可真的是“游戏”,甚至背后还有点哲学味儿:一个小小格子,活与死之间,全靠周围邻居的脸色。这设定,搁职场也没毛病。
今天咱们就来聊聊这道题,也不光是讲解怎么写,更重要的是搞清楚“这玩意儿到底是个啥”、“为啥这么设计”、“写这题我们能学到什么”。
先说题面,有点像是那种模拟题的典型套路:一个二维数组,每个位置是0或1,分别表示死细胞或活细胞。然后给你一堆规则,让你算出“下一时刻”的状态。但有个关键点不能忽略:所有变化必须同时发生。也就是说,你不能一边更新,一边让新状态去影响其他位置。
这就带来了个麻烦:我们不能直接在原数组上修改状态,否则你这个“现在是活的”还是“刚刚死的”根本搞不清。所以怎么存、怎么改、什么时候改,这里面其实是有技巧的。
我写这题的时候其实最早是想着暴力模拟,开一个新数组存结果,最后再整体赋值回去。看着简单,但空间复杂度上去了,刷题平台还不让用额外空间,就得换思路。
后来看了大佬写法,一个字:妙。
比如我们可以用两个中间状态来表示“即将死”和“即将活”:原本活细胞要死了,就先标个2;原本死细胞要复活,就标个3。等你所有格子都遍历完了,再走一遍把状态归位,2变成0,3变成1。
为什么这样做能保证“状态同步”?因为我们在判断某格子的邻居时,只看“原始状态”,也就是1(原来活)和0(原来死)。而中间态2和3虽然已经写进数组里了,但我们只在判断里取 Math.abs(board[x][y]) === 1 就可以只看原始的活细胞数量。是不是很巧妙?
我们可以简单用 JavaScript 来实现一下:
function gameOfLife(board) {
const m = board.length, n = board[0].length;
const dirs = [[-1, -1], [-1, 0], [-1, 1], [0, -1],
[0, 1], [1, -1], [1, 0], [1, 1]];
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
let liveNeighbors = 0;
for (const [dx, dy] of dirs) {
const x = i + dx, y = j + dy;
if (x >= 0 && x < m && y >= 0 && y < n) {
if (Math.abs(board[x][y]) === 1) {
liveNeighbors++;
}
}
}
if (board[j] === 1) {
if (liveNeighbors < 2 || liveNeighbors > 3) {
board[j] = 2; // 即将死亡
}
} else {
if (liveNeighbors === 3) {
board[j] = 3; // 即将复活
}
}
}
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (board[j] === 2) board[j] = 0;
else if (board[j] === 3) board[j] = 1;
}
}
}
这个写法我觉得是刷这题的最优解,原因也不复杂:逻辑清晰,不用额外空间,跑得快,写起来还不难。
其实很多人做这题的时候会有种错觉:这不就是个 if 判断加数组遍历的套路吗?有啥高级的?但我跟你说,这题真的是暴露基本功的照妖镜。你如果数组越界判断做不好、邻居遍历写不对、状态标记没想清楚,一定错得一塌糊涂。而且这题极度考验你对“状态同步”的理解,写着写着你就会意识到,这跟我们日常做并发、多线程处理其实是一个思想——不要让更新中的状态干扰到别人的判断。
而且,这题放在实际项目里,还真不是没用。我在之前做游戏服务端开发的时候,就碰到过类似场景。比如服务器端要做一波“区域广播”:每个玩家根据周围玩家状态变化来判断自己怎么行动。但每个玩家变化又可能反过来影响其他玩家……咋办?也是得先把“当前状态”拷贝出来算,不能边算边改。这题本质上就是个离散模拟 + 状态同步的经典案例,拿来练脑再合适不过了。
说到底,写算法题不是为了当搬砖工,是为了构建你脑子里的“解题套路”。像这题,明白了“状态不能直接修改”,那以后只要你看到“同时更新”这四个字,第一反应就该是——得搞中间态。
当然,还有更骚的写法,比如用位操作压状态,用个位记录当前状态,十位记录下一状态,之后用位运算恢复。我不是没试过,就是写完自己都不敢看,面试官可能直接问你:“你能读懂自己写的东西吗?”
写代码还是得 balance 一下,“骚”不等于“难以维护”。如果你是拿这题练习 JavaScript,那我还是推荐中间态标记法,实用且优雅。
总之,这道“生命游戏”表面看着像个玩具题,实际对状态模拟、边界处理、数组操作都有很高要求。如果你能把这题写得又快又准,还能讲清楚里面每个细节的设计理由,那我跟你讲,面试官多半会对你刮目相看。
写题不怕难,怕的是你写完之后不知道自己学到了什么。刷这题的意义,从来不是为了拿个AC,而是搞清楚:状态转换的问题该怎么拆、同步逻辑如何处理、代码要怎么写得既正确又清晰。
就像康威当年设计这游戏时说的:规则很简单,但演化却很复杂。而程序员写代码,不就是在给每个格子写命运吗?
写完这题,我不禁又想:如果每个程序员的职业生涯也是一个“生命游戏”,那我们的活跃状态,靠的可能不仅是自己努力,还得看周围的团队、环境、机会……但不管怎么说,只要我们还在活着,就还有下一步要走,不是吗?
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
🔥私藏精品🔥
虎哥作为一名老码农,整理了全网最全《前端资料合集》。总量高达650GB |
|