程序员老鬼

同事工资 2.5w,外企苟了9年,今年35岁,本来已经准备被裁,开始面试。结果一直裁不到,反而拿到阿里 offer涨薪50%~

刚看到个贴子,说有位网友同事在外企苟了9年,35岁,本来都准备躺平等裁了,结果愣是裁不到,反倒在面试时拿到阿里 offer,直接涨薪50%,现在反而纠结得不行。

Image

外企稳,但天花板肉眼可见;阿里薪资高,可压力也不会小,就像从舒适区跳进深水区,能不能游得动,全看心态和身体。

35岁能拿到大厂 offer,本身就是实力的体现。纠结正常,但别让“年龄焦虑”绑架了选择。钱多当然香,但长期能不能接受强度、对职业路径有没有帮助,也得掂量。

总之还是那句话:职场不是选最好的,而是选最适合自己的。只要方向选对了,路怎么走都不亏。【备注:文末可领最新资料】

面试题:字符串解码

我那天晚上加班到十一点多,准备收拾电脑走人,结果我们组小李微信问我:“哥,那个字符串解码的题你咋写的?我写着写着脑袋就乱了。”我一看题目,哦,经典面试题那个——"3[a2[c]]" 要解码成 "accaccacc",就是今天要聊的这个。

先把题目说清楚

大概长这样:

  • 输入是一个只包含数字、字母、[、] 的字符串
  • 格式像:3[a]2[bc]、3[a2[c]]、10[ab]x 这种
  • 数字表示后面那段在 [] 里的字符串要重复多少遍
  • 可以嵌套,可以多位数字

比如:

  • 3[a]2[bc] → aaabcbc
  • 3[a2[c]] → accaccacc
  • 2[ab3[c]]x → abcccabcccx

核心就是:一边从左往右扫,一边把“当前构造的串”和“当前的倍数”给记住,遇到 [、] 再进出栈。

怎么想这个过程?

你可以脑补自己在手动算:

看 3[a2[c]]:

  1. 看到 3,先记住这是个次数,等着用

  2. 看到 [,说明一个新的小世界要开始了,把刚才的“次数 3”和“此刻已经拼好的字符串(空串)”都压起来

  3. 然后在这个小世界里,从 a2[c] 开始继续扫

  • 先是 a,当前字符串就变成 "a"
  • 再遇到 2,先记住 2
  • 再遇到 [,又是一个更小的小世界,把当前 "a" 和 数字 2 再压一层
  • 进到 c,当前就是 "c"
  • 遇到 ],这个小世界结束了,把刚才的 "c" 按次数 2 拼成 "cc",再接到外面保存的 "a" 后面,变成 "a" + "cc" = "acc"
  • 再遇到外面那层 ],说明大世界也结束了,把 "acc" 按最外层次数 3 拼接,就成 "accaccacc"

  • 你会发现,每次遇到 [ 就“入栈”,遇到 ] 就“出栈并展开一次”,其他时间就是追加字母或构建数字。


    用两个栈就够了

    实现的时候,一般用:

    • 一个栈存「重复次数」:Stack<Integer> countStack

    • 一个栈存「之前的字符串」:Stack<StringBuilder> strStack

    • 再加上两个“当前变量”:

      • curNum:当前正在读的数字(注意要处理多位数字,比如 10[a])
      • curStr:当前这一层正在拼的字符串

    大致流程口水版说一遍:

    1. 字符是数字,就更新 curNum = curNum * 10 + (ch - '0')——这样 1、0 变成 10

    2. 字符是字母,就 curStr.append(ch)

    3. 字符是 [:

    • 把当前的 curNum 压到 countStack
    • 把当前的 curStr 压到 strStack
    • 然后 curNum 归零,curStr 换成新的空 StringBuilder,准备进入新一层
  • 字符是 ]:

    • 从 countStack 弹出一个次数 k
    • 从 strStack 弹出之前那层已经拼好的字符串 prev
    • 在一个新的 StringBuilder 里,把当前 curStr 重复 k 次拼上去
    • 然后把这个结果接到 prev 后面,赋值回 curStr = prev.append(repeated...)

    最后扫完一遍,curStr.toString() 就是答案。

    Java 实现直接给你一份

    publicclassDecodeString{

    public String decodeString(String s){
    // 栈:保存“倍数”和“之前的字符串”
            Deque<Integer> countStack = new ArrayDeque<>();
            Deque<StringBuilder> strStack = new ArrayDeque<>();

            StringBuilder curStr = new StringBuilder();
    int curNum = 0;

    for (int i = 0; i < s.length(); i++) {
    char ch = s.charAt(i);

    if (ch >= '0' && ch <= '9') {
    // 多位数字处理,比如 10[a]
                    curNum = curNum * 10 + (ch - '0');
                } elseif (ch == '[') {
    // 进入新的一层,当前状态先保存
                    countStack.push(curNum);
                    strStack.push(curStr);

    // 重置当前层
                    curNum = 0;
                    curStr = new StringBuilder();
                } elseif (ch == ']') {
    // 当前这层结束,展开一次
    int repeat = countStack.pop();
                    StringBuilder prev = strStack.pop();

                    StringBuilder temp = new StringBuilder();
    for (int k = 0; k < repeat; k++) {
                        temp.append(curStr);
                    }

    // 接回上一层
                    curStr = prev.append(temp);
                } else {
    // 普通字符,直接追加
                    curStr.append(ch);
                }
            }

    return curStr.toString();
        }

    // 随便测两下
    publicstaticvoidmain(String[] args){
            DecodeString d = new DecodeString();
            System.out.println(d.decodeString("3[a2[c]]"));   // accaccacc
            System.out.println(d.decodeString("2[ab3[c]]x")); // abcccabcccx
            System.out.println(d.decodeString("10[a]"));      // aaaaaaaaaa
        }
    }

    再啰嗦两句复杂度

    • 每个字符最多进一次栈、出一次栈,时间复杂度差不多就是 O(n)
    • 用到了两个栈,空间复杂度也是 O(n),主要花在栈和结果字符串上

    如果你更喜欢递归,也能写成递归版本,思路其实一样:遇到 [ 就递归进去,遇到 ] 就返回。但在面试里,非要二选一的话,我一般更倾向上面这个双栈版,可读、也不太容易写炸。

    好了,差不多就这样,你可以先照着敲一遍,再自己改一改变量名、自己手推一两个例子,基本这题就拿下了。

    -END-

    我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

    最后给大家分享一份不错的副业资料,点击下方公众号,回复关键字: 副业 领取,也可以链接我领取,微信:hls404