程序员老鬼

有个Leader年薪40万,最近招了一个刚进厂的新人,月薪24K,别的组不太看好,说他技术一般。Leader却很看重~

有网友吐槽:自己组里有个Leader年薪四十来万,最近却招了个刚入行的新人,开到两万四一个月。其他组私下并不买账,觉得这新人技术也就那样,性价比不高。

Image

可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 这种小例子把“高位/当前位/低位”的感觉说出来,面试官基本就点头了。哎我说着说着又饿了,算了不扯了,我先去翻下冰箱还有没有酸奶…