35岁大厂程序员上岸体制内,收入从百万年薪锐减到十几万后,妻子嫌弃他没上进心
刚看到个贴子,说一位朋友的老公在大厂干了8年,35岁考上公务员,本来百万年薪,结果一下子变成十几万。他自己觉得轻松稳定挺好,但老婆却嫌弃他没上进心 。
其实这个事情换个角度看,大厂的高薪其实是拿时间和健康换来的,每天加班到深夜,周末都没得休息。公务员虽然收入少了,但稳定、安全感、可支配的生活时间,都是隐形的“收益”。钱当然重要,可如果一直透支身体,迟早会把积蓄都搭进去。
网友们的评论我看了,有人觉得男人收入下降就是退步,也有人支持稳定生活。我比较认同后者:人生不同阶段追求不同,有的人拼钱,有的人拼健康,没谁是永远的标准答案。
总的来说还是要夫妻多沟通,别只盯着钱,能陪伴家人、身心健康,本身就是另一种进步。【备注:文末可领最新资料】
算法题:通过添加或删除结尾字符来同化字符串
昨天晚上十一点多,在公司楼下吹风,手机震了一下,小李问我一个看着很眼熟的问题——“哥,两个字符串怎么靠在一块儿啊,只能在尾巴上加字或者删字那种”。我当时困得脑袋嗡嗡的,但这事儿其实不绕,你们听我慢慢说,别着急,呃…我口水放这儿了。
先把场景讲清楚:有两个字符串 s 和 t,我们的手能做的就两件事,往某个串的末尾加一个字符,或者把末尾那个字符删掉。不能动中间,不能从前面抄近路。目标呢,就是让两个串最后一模一样。直觉怎么来?你把两个串从头往后对齐比一比,哪儿开始不一样了,后面那一截,总之都得靠删掉或者补上去解决。对吧,这时候脑子里会蹦出一个词,那个…叫什么来着…哦对“最长公共前缀”。从下标0开始一路相等的那段,就是“能保住”的骨架,后面的都算尾巴。
所以最少操作数其实特别朴素:先找出 s 和 t 的最长公共前缀长度 lcp。s 多出来的尾巴要删掉 len(s) - lcp 次;要是你打算把 s 变成 t,还得给 s 把 t 的尾巴补回去 len(t) - lcp 次。你也可以反过来操作 t,或者俩都删到公共前缀停下,也行,账一算都是 (len(s) - lcp) + (len(t) - lcp)。有人会问能不能更省?不行,因为前缀之外的字符用我们这两种手法,必须一个个尾部处理,没法跳。
等等我接个电话……好了继续。实现也就两步,先线性扫一遍求 lcp,再按上面的式子出答案。复杂度 O(n),n 是两串里较短的长度,空间 O(1)。边界呢,别忘了空串,如果其中一个是空串,那 lcp=0,结果就是另一个串的长度;如果俩串本来就一样,lcp=两者长度,结果就是0,完事儿走人。还有大小写、Unicode 这些,按字符逐个比就好,Java 的 char 是 UTF-16 code unit,遇到表情这种代理项可能会有“一个用户视觉字符等于两个 char”的情况,如果业务关心“人眼的字形”,可以换成基于 codePoint 的遍历,不过今天就不展开了,太困。
我把代码贴下,你们直接抄…啊不是,直接拿去跑。写得直给点:
publicclassAssimilateStrings{
// 计算最少操作数:只能对末尾做添加或删除,使两个字符串相同
publicstaticintminOps(String s, String t){
if (s == null) s = "";
if (t == null) t = "";
int lcp = longestCommonPrefixLength(s, t);
return (s.length() - lcp) + (t.length() - lcp);
}
// 线性求最长公共前缀长度
privatestaticintlongestCommonPrefixLength(String s, String t){
int n = Math.min(s.length(), t.length());
int i = 0;
while (i < n && s.charAt(i) == t.charAt(i)) {
i++;
}
return i;
}
// 如果你真要给出一步步变换,也能模拟一下过程(把 s 变成 t)
publicstatic String[] transformSteps(String s, String t) {
int lcp = longestCommonPrefixLength(s, t);
StringBuilder cur = new StringBuilder(s);
java.util.List<String> steps = new java.util.ArrayList<>();
while (cur.length() > lcp) { // 删到公共前缀
cur.deleteCharAt(cur.length() - 1);
steps.add(cur.toString());
}
for (int i = lcp; i < t.length(); i++) { // 补上 t 的尾巴
cur.append(t.charAt(i));
steps.add(cur.toString());
}
return steps.toArray(new String[0]);
}
publicstaticvoidmain(String[] args){
String s1 = "abca";
String t1 = "abcxyz";
System.out.println(minOps(s1, t1)); // 1删 + 3加 = 4
String s2 = "";
String t2 = "hello";
System.out.println(minOps(s2, t2)); // 5
String s3 = "same";
String t3 = "same";
System.out.println(minOps(s3, t3)); // 0
// 看看具体变换
String[] steps = transformSteps(s1, t1);
for (String st : steps) System.out.println(st);
}
}
顺嘴再补两句,万一输入很长,比如十万字符,别怕,这里只有一次顺序扫描,缓存压力也小;要是有人非要把很多对字符串一起算,那就把 lcp 那段逻辑封成内联方法,JIT 会把它优化得还挺狠。还有一个小坑,若你们在流式比对里字符一个个到达,也可以维护一个“当前已确认前缀长度”,一旦遇到不等就锁定 lcp,其它都按照上面的套路走。好了我先去热个咖啡,脑袋要炸了,等会儿谁要是跑出啥奇怪 case 发我下,我看下是不是我键盘又抽风了。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html