程序员老鬼

面了个要28K的候选人,简历写精通Linux/Shell。 我让他现场写个命令:乡统计Nginx日志里访问量Top10的IP。他憋了半天,写了个cat

刚看到个贴子,说有公司面了个开口就要28K的候选人,简历上写着“精通Linux/Shell”。面试官随手让他现场写个命令,统计一下Nginx日志里访问量Top10的IP,结果这哥们憋半天,只敲出一个cat,awk不会,sort不会,uniq也不会,现场直接尴尬静音。

Image

我觉得这事关键不在28K,也不在题难不难,而是在“精通”这俩字上。要价高可以,只要你真有货;但要是平时就只会敲几句常用命令,还非要在简历上写“精通”,那不叫自信,叫给自己挖坑。

换个角度讲,面试官出这类题也正常,毕竟公司是花钱买能力的,不是买PPT上的形容词。与其在简历上堆“精通”“专家”,不如老老实实打好基本功。

面试题:整数转罗马数字

昨天晚上十一点多,我在公司楼下等外卖,正刷手机呢,我们组那个小李突然发语音过来:

“东哥东哥,那个……整数转罗马数字你会不,会的话赶紧救救我,明天面试要考的那种,语言用 Java 的……”

我一看这玩意儿,典型面试常客嘛,不过确实,第一次写的时候很多人都会写得乱七八糟。

简单记几个符号就行,不要死背表:

  • I = 1
  • V = 5
  • X = 10
  • L = 50
  • C = 100
  • D = 500
  • M = 1000

有两个“怪脾气”的规则,一定得记清:

  • 4 不是 IIII,而是 IV(小在左边表示减)

  • 9 不是 VIIII,而是 IX

  • 同理:

    • 40 = XL
    • 90 = XC
    • 400 = CD
    • 900 = CM

一般面试题默认输入范围是 1 ~ 3999,超过的先别管,老老实实写好这一段就行。

当时我就跟小李说:你别想着写一坨 if-else:

if (num >= 1000) ...
elseif (num >= 900) ...
...

这种最后自己都看不下去。

更舒服一点的写法,是把“值”和“符号”配成两行数组,从大到小,一个个往下减,属于典型贪心思路:

每次能用最大的符号就一直用它,用完再换小一点的。

比如 1994:

  • 先用 1000 -> M,剩下 994
  • 能用 900 -> CM,剩下 94
  • 能用 90 -> XC,剩下 4
  • 能用 4 -> IV,结束,拼出来就是 MCMXCIV

这个套路跟线上拆包、拆任务其实一个味道:一段一段往下啃。

我当时就把这段丢给小李,你可以直接照着写、再自己敲几遍记下手感:

publicclassIntToRoman{

// 从大到小排好,包含那些“特殊值”:900、400、90、40、9、4
privatestaticfinalint[] VALUES = {
1000, 900, 500, 400,
100, 90, 50, 40,
10, 9, 5, 4, 1
    };

privatestaticfinal String[] SYMBOLS = {
"M", "CM", "D", "CD",
"C", "XC", "L", "XL",
"X", "IX", "V", "IV", "I"
    };

/**
     * 把 1~3999 的整数转成罗马数字
     */

public String intToRoman(int num){
        StringBuilder sb = new StringBuilder();
// 一路从大到小贪心
for (int i = 0; i < VALUES.length && num > 0; i++) {
int value = VALUES[i];
            String symbol = SYMBOLS[i];
// 能减多少次就减多少次
while (num >= value) {
                num -= value;
                sb.append(symbol);
            }
        }
return sb.toString();
    }

// 随便写个 main 自测一下
publicstaticvoidmain(String[] args){
        IntToRoman solution = new IntToRoman();
        System.out.println(solution.intToRoman(3));     // III
        System.out.println(solution.intToRoman(4));     // IV
        System.out.println(solution.intToRoman(9));     // IX
        System.out.println(solution.intToRoman(58));    // LVIII
        System.out.println(solution.intToRoman(1994));  // MCMXCIV
    }
}

这个实现几个点你心里有数就行:

  • 时间复杂度其实算 O(1):因为 VALUES 长度是固定的 13,最多 while 里循环几次而已
  • 不用管“连续最多三个 I、X、C、M 之类”的规则,因为我们数组本身就是按规范设计的,不会生成非法串
  • StringBuilder 一定要用,别在循环里无脑 + 拼字符串,面试官会叹气的

行,我这会儿也困得不行了,就先写到这。你把这段 Java 多敲几遍,关掉编辑器,自己默写一遍思路:

“从大到小枚举所有合法数值,能减就减,减完拼字符串”

能把这句话说顺溜,这题基本就拿下了。剩下的,你就自己开 IDE 玩去,我先去冲杯咖啡再干活了。