程序员老鬼

某大厂员工吐槽:单位新来的00后嫌椅子不舒服,自己买了把一千多人体工学椅,老员工看到后沉默了,自己忍了十几年只买了靠垫!

新来的00后也是真敢整。刚入职没几天,先嫌公司椅子坐着腰疼,转头自己下单一把一千多的人体工学椅,第二天直接搬到工位。旁边那帮老员工看了一眼,集体“啧啧啧”,然后全沉默了。

Image

老一辈打工人那套逻辑就是:忍,凑合,垫个靠垫已经算对自己好了。腰不舒服?那就站起来走两步。脖子酸?说明最近活多。反正十几年都这么熬过来了。

结果00后不跟你演这个苦情戏。坐得不舒服,我就换。身体是自己的,班是公司的。评论区也有人说,这代人不是娇气,是算明白账了,花一千块保住腰,比以后去医院理疗便宜多了。还有人补刀,说老员工不是不想买,是早被“能用就行”这四个字驯服了。

面试题:转置文件

文件一大,很多人第一反应就是把所有内容先读进 List<String>,再按列去拼。这个写法在本地跑小样例没问题,真丢到几十 MB 甚至更大的文本上,内存先开始不老实。

“转置文件”这题其实不复杂,难点不在算法本身,在你是不是一上来就把题目想歪了。它本质上不是矩阵转置,也不是二维数组题,而是按行读、按列吐。输入像这样:

name age city
tom 18 bj
jack 20 sh

转置后要变成:

name tom jack
age 18 20
city bj sh

也就是说,第 1 行的第 1 个单词、第 2 行的第 1 个单词、第 3 行的第 1 个单词,最后要落到同一行里。

我一般先盯两个点:

第一,分隔符是不是固定空格。很多人直接 split(" "),这就埋坑了,连续空格会切出空串。这里更稳一点,直接上 split("\\s+")。

第二,不同行的字段数可能不一样。你以为每行都是 3 列,结果线上文件第四行少个字段,代码就数组越界了。这种题别太信输入一定规整,防一手不吃亏。这个判断习惯,做久了线上排障自然就有了。

下面这版我自己会这么写,思路很直接:先把每一行拆成数组,顺手记下最大列数;然后第二轮按列拼接输出。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

publicclassMain{

publicstaticvoidmain(String[] args)throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        List<String[]> rows = new ArrayList<>();
        String line;
int maxCols = 0;

while ((line = reader.readLine()) != null) {
            line = line.trim();
if (line.isEmpty()) {
continue;
            }

            String[] parts = line.split("\\s+");
            rows.add(parts);
if (parts.length > maxCols) {
                maxCols = parts.length;
            }
        }

        StringBuilder out = new StringBuilder();

for (int col = 0; col < maxCols; col++) {
            StringBuilder currentLine = new StringBuilder();

for (String[] row : rows) {
if (col < row.length) {
if (currentLine.length() > 0) {
                        currentLine.append(' ');
                    }
                    currentLine.append(row[col]);
                }
            }

            out.append(currentLine).append('\n');
        }

        System.out.print(out);
    }
}

这段代码有几个地方是故意这么写的。

line.trim() 先收一下,避免首尾空格影响判断。空行直接跳过,不参与转置,不然后面会多出一些莫名其妙的空列。

maxCols 单独记,不要后面临时扫,不然逻辑散。还有一点,输出时我没在循环里硬控最后一个空格,而是通过 currentLine.length() > 0 来决定要不要补空格,这种写法比“先拼接再删最后一个空格”稳,少一点边界判断。

时间复杂度不高,核心就是遍历两遍单词,算 O(m * n),m 是行数,n 是最大列数。空间复杂度主要花在存储原始分词结果上。

当然,这题还有人喜欢边读边转,把第 1 列、第 2 列、第 3 列分别塞到不同的 StringBuilder 里,那样也能做,而且更省一次遍历。只是代码会稍微绕一点,面试里未必划算。题不大,先把正确性和边界守住,比炫技巧重要。

这种题看着像字符串处理,真写起来,翻车点永远还是那些:空格、空行、列数不齐。代码短,不代表可以糊弄。