年薪90万,税后到手也就68万,天天加班到凌晨一点,回家还被老婆数落,家里柴米油盐、人情往来全是老婆打理,算到年底居然只存了20万出头
刚看到个贴子:有哥们年薪90万,税后68万,天天加班到凌晨一点,回家还被老婆数落“拿命换钱”,平时省吃俭用,一年底一算只存了二十来万,心态直接崩。
这事背后是典型的“看着光鲜、实际困顿”。房贷、车贷、老人小孩、人情往来,一样都不便宜,钱就跟下水道一样哗啦啦流。
从我的角度看,关键有三点: 第一,夫妻得把账摊开算清楚,钱到底花哪了,不要只靠情绪吵。 第二,想明白阶段目标,是先拼本金,还是先保身体和家庭关系。 第三,公司真是拿命换钱、又看不到出口,那就得早点谋退路。
面试题:自定义字符串排序
昨天晚上快十一点了,我在公司楼下啃着外卖,产品突然微信我一句:”东哥,这个列表能不能按我们自己定的顺序排一下,不是字典序那种。“我当时就笑了,这不就是经典的“自定义字符串排序”嘛。
先把题目用人话说清楚哈: 给你两个字符串:
order:表示“我想要的字符优先级顺序”,比如"cba"s:原始字符串,比如"abcd"
要求是:把 s 里的字符,按照 order 里给的顺序排好,order 里没提到的字符就随便丢后面就行。 上面这个例子,结果就是 “cbad”,因为 c 在前,b 第二,a 第三,d 没在规则里就排最后。
我一般会先用一种好理解、好写、性能也不错的写法:计数 + 拼接,就像先数清楚有哪些菜,再按顺序装盘。
你可以想象一张“统计表”:
先扫一遍 s,把每个字符出现次数记下来。然后按 order的顺序,把这些字符一个个按“记的次数”拼到结果里。最后,把那些 order没提到,但在s里出现过的字符,也按它们本来的样子补到后面。
这个过程就完全符合产品的要求了,而且时间复杂度其实就是 O(n),n 是 s 的长度。
先写一个通用一点的版本,支持所有 ASCII 字符,不只小写字母:
publicclassCustomSort{
// 核心方法:按 order 里面的顺序,对 s 进行自定义排序
public String customSortString(String order, String s){
// 简单粗暴:开 256,够 ASCII 用了
int[] cnt = newint[256];
// 1. 统计 s 里每个字符的次数
for (char c : s.toCharArray()) {
cnt[c]++;
}
StringBuilder sb = new StringBuilder();
// 2. 先按照 order 的顺序,把对应字符都拼上去
for (char c : order.toCharArray()) {
while (cnt[c] > 0) {
sb.append(c);
cnt[c]--;
}
}
// 3. 把剩下的、order 里没定义的字符也补上去
for (int i = 0; i < 256; i++) {
while (cnt[i] > 0) {
sb.append((char) i);
cnt[i]--;
}
}
return sb.toString();
}
publicstaticvoidmain(String[] args){
CustomSort cs = new CustomSort();
String order = "cba";
String s = "abcd";
System.out.println(cs.customSortString(order, s)); // 输出 cbad
}
}
这个写法几个点你脑子里过一下就行:
cnt[c]里就存着字符c在s中出现了多少次第一个循环干完后,所有字符都被记账了 第二个循环严格按 order排序、并且每次 append 会把对应计数减掉最后一个循环扫一遍所有字符,把没用完的都补上去,顺序就“无所谓”了,题目也不要求
如果你确定题目只会给你小写字母 'a' ~ 'z',那数组可以开成 int[26],索引用 c - 'a',更节省一点。
上面这个是偏“算法题”一点的写法。但我工作里遇到的,有时候是“对象列表”要自定义排序,比如按“城市优先级”、“频道优先级”之类,这时候计数数组就不太好用了,更常见的是写一个自定义比较器。
比如把“字符优先级”抽成一个 rank 表,然后交给 Arrays.sort 去排:
public String customSortString2(String order, String s){
// 1. 先把每个字符在 order 里的优先级记下来
Map<Character, Integer> rank = new HashMap<>();
for (int i = 0; i < order.length(); i++) {
rank.put(order.charAt(i), i); // 越靠前优先级越高
}
// 2. Java 想自定义排序得用包装类型
Character[] arr = new Character[s.length()];
for (int i = 0; i < s.length(); i++) {
arr[i] = s.charAt(i);
}
// 3. 自定义比较器:没出现在 order 里的,统一给个很大的 rank
Arrays.sort(arr, (a, b) -> {
int ra = rank.getOrDefault(a, Integer.MAX_VALUE);
int rb = rank.getOrDefault(b, Integer.MAX_VALUE);
return Integer.compare(ra, rb);
});
// 4. 再拼成字符串
StringBuilder sb = new StringBuilder(arr.length);
for (char c : arr) {
sb.append(c);
}
return sb.toString();
}
这个思路跟我们平时给“状态”、“等级”这些东西排优先级是一个套路:先映射成数字,再用比较器搞定。写复杂业务排序的时候,也可以直接套这个思路,字符换成对象、rank 换成各种业务权重就行了。
总之,这道“自定义字符串排序”,你如果能把上面两种写法都吃透,以后产品说“我要按我说的顺序来排”,你心里就一点都不慌了,顶多吐槽一句:你早点说啊,我都准备下班了…
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html