程序员老鬼

上个月招人,遇到个35岁、背景优秀但技术栈稍显传统的后端候选人。技术面很扎实,能解决复杂问题,结果领导说。。。

刚看到个贴子,说公司招人时遇到一位35岁的后端候选人,技术功底很扎实,但因为技术栈偏传统,VP一句“怕学不动新东西了”,就打算放弃。🤦‍♂️

Image

我觉得这逻辑挺荒唐的。学不学得动,真和年龄没必然关系。我们写代码的都知道,框架换来换去,底层思维其实没啥变。一个能在复杂系统里稳住场面的人,比起只会写几个新潮API的“速成选手”,价值往往更高。

网友里也有人认同“年轻人学习快”,但我更认同另一种声音:企业真正要的不是跟风,而是能把问题解决掉的人。就像开发中遇到线上故障,你是要一个能快速修复的老手,还是一个能写炫酷语法但一慌就懵的新人?

所以说,招聘时别被“35岁焦虑”绑架。关键是能不能持续创造价值。技术迭代是快,但人的学习能力和解决问题的经验,也是一种不会过时的核心竞争力。【备注:文末可领最新资料】

算法题:变更性别

昨天晚上十一点多,在公司楼下吹风,手机里有人问:“老东,那个用户性别批量改来改去,怎么写才不慢?”我当时脑子里一激灵——就是那个…怎么说呢…把一串M/F不停翻转嘛,对吧,有时候一段区间都要改,偶尔还要临时查某个人现在到底是男是女。手抖别用朴素循环,一个个改,q次操作打下来分分钟超时。

你们知道吧,翻转其实就是“取反”的意思。把M当0、F当1(或者反过来也行),翻一下就是和1做个异或。区间翻转呢?我不想每次把[l,r]都走一遍,太累。就用“差分 + 前缀异或”这个小把戏: 在diff[l] ^= 1,diff[r+1] ^= 1,最后一路前缀异或回去,就得到每个位置被翻了奇数次还是偶数次。这样q个区间操作只改两个点,舒服。 要是中途还老有人问“第i个现在啥性别”,那我就再上一个树状数组(Fenwick),同样存翻转次数的差分,区间加、单点查,查到前缀和的奇偶性就知道翻没翻过。嗯…对了刚才说到哪了?对,奇偶性,记得模2。

import java.io.*;
import java.util.*;

publicclassMain{
staticclassBIT{
int n; int[] t;
        BIT(int n){ this.n = n; t = newint[n+2]; }
voidadd(int i, int delta){
for(; i<=n; i+=i&-i) t[i] += delta;
        }
// 范围[l,r]翻转:+1 和 -1 差分
voidrangeFlip(int l, int r){
            add(l, 1);
if(r+1<=n) add(r+1, -1);
        }
intprefix(int i){
int s = 0;
for(; i>0; i-=i&-i) s += t[i];
return s;
        }
booleanflipped(int i){ // true = 被翻奇数次
return (prefix(i) & 1) == 1;
        }
    }

// 把字符映射到0/1,最后再往回映射
staticchartoggle(char c){ return c=='M' ? 'F' : 'M'; }

publicstaticvoidmain(String[] args)throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 输入示例:
// n q
// MFMFF
// op...
// 约定:1 开始索引
        String[] first = br.readLine().trim().split("\\s+");
int n = Integer.parseInt(first[0]);
int q = Integer.parseInt(first[1]);
char[] s = (" "+br.readLine().trim()).toCharArray(); // 占位让索引从1
        BIT bit = new BIT(n);

        StringBuilder out = new StringBuilder();
for(int k=0;k<q;k++){
            String line = br.readLine();
if(line==null || line.isEmpty()){ k--; continue; }
            String[] op = line.split("\\s+");
if(op[0].equals("F")){ // F l r  :区间翻转
int l = Integer.parseInt(op[1]);
int r = Integer.parseInt(op[2]);
if(l>r){ int t=l; l=r; r=t; }
                bit.rangeFlip(l, r);
            }elseif(op[0].equals("Q")){ // Q i :查询第i位当前性别
int i = Integer.parseInt(op[1]);
char ans = bit.flipped(i) ? toggle(s[i]) : s[i];
                out.append(ans).append('\n');
            }
        }

// 如果需要最后整串结果,也可以一次性还原
// 这里演示一下,非必需
// 注:若q里没有“Q”,你们就把下面这段打印出来当最终串
//StringBuilder fin = new StringBuilder(n);
//int carry = 0;
//for(int i=1;i<=n;i++){
//    carry ^= bit.prefix(i) & 1;
//    fin.append(carry==1 ? toggle(s[i]) : s[i]);
//}
        System.out.print(out.toString());
    }
}

边界啊,注意下标我用的是从1开始,输入的时候前面拼了个空格占位,别学我粗心搞成0/1混着用。还有,区间[l,r]如果l>r,我顺手交换一下,省得调用的人写错。时间复杂度这块儿,区间翻是O(log n)一次,点查询也是O(log n),如果最后一次性还原整串,就是O(n log n)的查前缀,其实也行;但更省的是直接“差分数组+前缀异或”线性还原,那个是O(n),就是…看你们需求呗。

-END-

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

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