有个Leader年薪40万,最近招了一个刚进厂的新人,月薪24K,别的组不太看好,说他技术一般。Leader却很看重~
有网友吐槽:自己组里有个Leader年薪四十来万,最近却招了个刚入行的新人,开到两万四一个月。其他组私下并不买账,觉得这新人技术也就那样,性价比不高。
可Leader态度很坚定,说他更想要“反应快”的人,而不是只会按套路写代码、把逻辑堆漂亮的人。
我倒能理解这种选择。很多岗位拼的不是背题和手速,而是遇到新问题能不能迅速抓重点、敢试错、能沟通、能推进。技术当然重要,但技术是可以训练的;而学习能力、抗压和责任心,反而更稀缺。
面试题:数字 1 的个数
昨晚加班到快十点吧,电梯里信号还断断续续的,群里有人甩了个算法题给我:数字 1 的个数。就那种看着很“幼儿园”,结果一写就容易写成暴力循环,n 一大直接把你机器风扇干起飞那种…我当时脑子也木,差点就准备 for(i=1..n) toString 了,后来想想不对啊,这玩意儿面试官就等你上钩呢。
我就拿手机当草稿纸,随手写了个例子:比如 n=13,从 1 到 13 里,1 出现多少次?1(1次) 10(1次) 11(2次) 12(1次) 13(1次) 一共 6。这个答案大家都能背,但关键是 n=10^9 你咋办,对吧…你要是还在那一位位扫,真就“生产环境故障排查全记录”了。
这个题的味道其实跟“按位拆”差不多,就是站在某一位上看它对结果的贡献。比如你盯着个位、十位、百位…每一位都能算出来这一位上会出现多少个 1,然后加起来就行。核心就是把 n 拆成三段:高位 high、当前位 cur、低位 low。 举个十位的例子:n=abcde,当前位是 c(十位/百位看你定),high 是左边那坨,low 是右边那坨。
规律我当时是这么记的(有点口糊哈):
cur = 0:这一位的“1”出现次数 = high * factor cur = 1:次数 = high * factor + (low + 1) cur > 1:次数 = (high + 1) * factor factor 就是 1、10、100… 你在算哪一位就是哪个。
行,代码我给你们贴个 Java 的,别整 int 溢出那种尴尬,我直接用 long,反正稳一点。你们复制跑一下就懂了。
publicclassCountDigitOne{
// 统计 1..n 之间,数字 '1' 出现的次数
publicstaticlongcountDigitOne(long n){
if (n <= 0) return0;
long ans = 0;
for (long factor = 1; factor <= n; factor *= 10) {
long low = n % factor;
long cur = (n / factor) % 10;
long high = n / (factor * 10);
if (cur == 0) {
ans += high * factor;
} elseif (cur == 1) {
ans += high * factor + (low + 1);
} else {
ans += (high + 1) * factor;
}
// 防一手 factor *= 10 溢出(虽然一般题目 n 不会到 long 极限)
if (factor > Long.MAX_VALUE / 10) break;
}
return ans;
}
// 小测一下
publicstaticvoidmain(String[] args){
System.out.println(countDigitOne(13)); // 6
System.out.println(countDigitOne(1)); // 1
System.out.println(countDigitOne(0)); // 0
System.out.println(countDigitOne(99)); // 20
System.out.println(countDigitOne(100)); // 21
System.out.println(countDigitOne(101)); // 23
}
}
我当时在地铁上还顺手验了下 99 为啥是 20:个位上 1 出现 10 次(1,11,21...91),十位上也 10 次(10~19),加起来 20,嗯对得上。100 就多了那个“百位的 1”,所以 21。你看这种按位算的好处就是…不会被 n 的大小吓到,循环次数就跟位数走,最多也就十几次。
反正这个题你要是现场讲,别一上来背公式,先拿 13、99 这种小例子把“高位/当前位/低位”的感觉说出来,面试官基本就点头了。哎我说着说着又饿了,算了不扯了,我先去翻下冰箱还有没有酸奶…