程序员老鬼

知乎高问:965月薪18k有必要跳槽大厂30k吗?

刚看到个贴子,说一哥们在北京,965月薪18k,不加班不裁员,就是两年没涨薪,现在拿到大厂30k的offer,纠结要不要跳。

Image

我觉得这事吧,主要看你追求啥。如果图稳定、生活平衡,那现在这份工是真的香,四小时干活还能拿18k,北京能过得挺滋润的。但要是你想提升技术、拓展眼界,那跳槽去大厂确实是条捷径——不过得准备好被“加班文化”卷进去了。

网友们有的说“钱多才是硬道理”,也有人劝“好日子别轻易丢”。我倒觉得关键是看你当前阶段的目标。如果你还年轻,有冲劲,那可以去闯一闯;但若你现在正想稳下来,就别被数字诱惑。【备注:文末可领最新资料】

算法题:Lisp 语法解析

说个场景先哈——昨天晚上十一点多,我在公司楼下啃汉堡,手机里有人问:“哥,面试要我手写个 Lisp 解析器,用 Java,咋整?”我一想,这不就括号地狱嘛…但别慌,套路很稳。

Lisp 的核心其实就三样:原子(数字、符号、字符串)、列表((a b (c d)))、引号('x 等于 (quote x))。目标是把源码变成一棵 AST,然后你愿意再做解释执行也行,不愿意就停在 AST 也能交差。

先分词:括号单独成词,字符串要成对儿,空白分隔。再递归下降:

  • 遇到 ' 就把后面那个表达式包成 (quote …)。
  • 遇到 ( 就一直读到匹配的 ),生成 List 节点。
  • 其他就是 Atom。 有个小坑:要报告未闭合括号、非法字符串,面试官最爱问的就是这些边界。

Java 代码

import java.util.*;
classLispParser{
// --- AST ---
interfaceNode{ }
staticfinalclassAtomimplementsNode{
final String lexeme;
        Atom(String s){ this.lexeme = s; }
public String toString(){ return lexeme; }
    }
staticfinalclassListNodeimplementsNode{
final List<Node> children = new ArrayList<>();
public String toString(){ return children.toString(); }
    }

// --- Lexer ---
static List<String> tokenize(String src){
        List<String> out = new ArrayList<>();
int n = src.length();
for(int i=0;i<n;){
char c = src.charAt(i);
if(Character.isWhitespace(c)){ i++; continue; }
if(c=='('||c==')'||c=='\''){ out.add(String.valueOf(c)); i++; continue; }
if(c=='"'){ // string
int j=i+1; StringBuilder sb=new StringBuilder();
while(j<n && src.charAt(j)!='"'){
if(src.charAt(j)=='\\' && j+1<n){ sb.append(src.charAt(j+1)); j+=2; }
else { sb.append(src.charAt(j++)); }
                }
if(j>=n) thrownew RuntimeException("Unclosed string");
                out.add("\""+sb.toString()+"\"");
                i=j+1; continue;
            }
// symbol/number
int j=i;
while(j<n){
char d=src.charAt(j);
if(Character.isWhitespace(d) || d=='('||d==')'||d=='\'') break;
                j++;
            }
            out.add(src.substring(i,j));
            i=j;
        }
return out;
    }

// --- Parser ---
staticfinalclassP{
final List<String> t; int i=0;
        P(List<String> t){ this.t=t; }
booleanend(){ return i>=t.size(); }
String peek(){ return t.get(i); }
String pop(){ return t.get(i++); }

Node parseExpr(){
if(end()) thrownew RuntimeException("Unexpected end");
            String tok = peek();
if("'".equals(tok)){ // quote
                pop();
                ListNode q = new ListNode();
                q.children.add(new Atom("quote"));
                q.children.add(parseExpr());
return q;
            }
if("(".equals(tok)){
                pop();
                ListNode list = new ListNode();
while(!end() && !")".equals(peek())){
                    list.children.add(parseExpr());
                }
if(end()) thrownew RuntimeException("Unclosed paren");
                pop(); // )
return list;
            }
if(")".equals(tok)) thrownew RuntimeException("Unexpected )");
returnnew Atom(pop());
        }
    }

// demo
publicstatic Node parse(String code){
        List<String> tk = tokenize(code);
        P p = new P(tk);
        Node root = p.parseExpr();
if(!p.end()) thrownew RuntimeException("Trailing tokens from: "+p.peek());
return root;
    }

publicstaticvoidmain(String[] args){
        String code = "(define square (lambda (x) (* x x)))";
        System.out.println(parse(code));
        System.out.println(parse("'(1 2 \"hi\")"));
    }
}

数字和符号现在都进了 Atom,要区分类型,面试时你可以在 Atom 里多存个 kind;字符串我保留了引号,真实业务会存原始值;错误信息一定要给到点,比如哪一位出错。行了我得去接个电话…总之这版能把 Lisp 的基本语法稳稳解析下来,够用也好讲。

-END-

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

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