刚看到个贴子,说一面试官吐槽:面了个要28K的候选人,简历上写“精通Linux/Shell”,结果现场让他写个统计 Nginx 日志里访问量前10的IP,憋半天只打出个 cat,awk、sort、uniq全不会。

网友回帖我看了看,大概两派:一派说这候选人明显“标题党”,要高薪还不肯下功夫练基本功;另一派觉得面试官题出得太“抠细节”,像是在抓小辫子,真工作里谁不会现查。
我觉得这事吧,关键不在那条命令,而在“诚实”二字。要28K,其实是在告诉公司:我能独立搞定一类问题,那至少常用工具得玩得转;真不会就别写“精通”,写“了解/熟悉”没人笑你。反过来,公司也别指望一道命令就看穿一个人,多问他怎么思考、怎么排查问题。
算法题:整数转罗马数字
昨天晚上快十一点,我在公司楼下便利店等微波炉叮——的时候,刷了一眼群里,有个同事扔了句:谁帮我看下“整数转罗马数字”这题,用 Ruby 写?我当时一愣,这题不是挺经典的吗,正好趁热打个小稿子,顺便聊聊我自己是怎么想的。
先说清楚这个题在干嘛哈:给你一个整数,通常范围是 1 到 3999,然后让你输出罗马数字,比如 3 变成 "III",4 是 "IV",9 是 "IX",58 是 "LVIII",1994 是 "MCMXCIV" 这种。看着有点古罗马那味儿,但规则其实不多。
罗马数字里就那几个基本符号:I=1,V=5,X=10,L=50,C=100,D=500,M=1000。然后有个小坑,就是有些数字是“减法写法”,比如 4 不是 "IIII" 而是 "IV",9 是 "IX",40 是 "XL",90 是 "XC",400 是 "CD",900 是 "CM"。也就是说,小的在大的左边就表示减,大的左边顶多放一个小的。规则就这些,记住就行。
那怎么把一个整数变成这一串符号呢?我一开始也想过那种“硬编码”:判断 num >= 1000 就减 1000 拼个 "M",然后再看 >=900 拼 "CM"……写一堆 if。能写,但是代码会很丑,而且很长,一眼看过去就想关 IDE。
比较舒服的做法,是准备一张“对照表”,把所有可能用到的数值和符号一一列好,从大到小排一遍,然后一路贪心往下减。比如值这边:1000、900、500、400……一直到 1;符号这边:M、CM、D、CD……一直到 I。
用 Ruby 写出来大概是这样:
defint_to_roman(num) values = [1000, 900, 500, 400,100, 90, 50, 40,10, 9, 5, 4, 1] symbols = ["M", "CM", "D", "CD","C", "XC", "L", "XL","X", "IX", "V", "IV", "I"] result = +"" i = 0while num > 0while num >= values[i] num -= values[i] result << symbols[i]end i += 1end resultend这个思路特别直观:从 1000 开始看,能减就减,减一次就往结果里塞一次对应的罗马字符。减到不够减了,就换下一个值继续。num 最终会被减到 0,result 就是答案。
随便走一遍 1994,你脑子里跟一下: 先看 1000,够,就减一次,拼 "M",此时 num=994; 再看 900,够,就减一次,拼 "CM",num=94; 再看 500、400 都不够,跳过; 看 90,够,拼 "XC",num=4; 看 4,刚好,拼 "IV",num=0;出来就是 "MCMXCIV"。整套逻辑就这么一路往下扫,很顺。
复杂度上,其实这个做法是 O(1) 的,因为最大就 3999,循环次数有上限;如果你非要从数学角度说,也是和位数有关,差不多 O(logN) 那个意思。反正面试官一般不会在这个题上较真复杂度,更多是看你代码是不是又短又清晰。
还有一种写法,也挺香的,就是按“千、百、十、个”四位直接查表。因为每一位能出现的罗马组合其实就那几种: 比如百位只有 0、100、200……900 这十种情况,你可以直接把这十种字符串放进数组里,按数字索引拿就行。Ruby 写出来是这样:
defint_to_roman(num) thousands = ["", "M", "MM", "MMM"] hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"] tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"] ones = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"] t = num / 1000 h = (num % 1000) / 100 te = (num % 100) / 10 o = num % 10 thousands[t] + hundreds[h] + tens[te] + ones[o]end这个版本的好处就是:没有循环,看上去就是纯拼接,读起来也很舒服,而且不太容易写错。坏处嘛,就是需要一开始把四个数组好好敲一遍,不过敲一遍之后就一劳永逸了。
实际工作里我更喜欢第二种,查表法,尤其是那种“输入范围死死的”的题,表格一铺开,逻辑特别干净。如果是刷题刚上手,其实第一种贪心写法更锻炼你对“规则抽象成数据结构”的感觉,两种都写一遍,印象会很深。
行,整数转罗马数字差不多就这样,我先去给自己续个咖啡,你要是哪一步没绕明白,可以直接拿这两个 Ruby 方法跑一跑,多打几个例子就通了。
🔥编程资料合集🔥