题目描述

✅ 194. 转置文件

image-20260928233525855

题意分析

文件中每一行由空格分隔成若干字段,各行字段数量相同。要求将原文件每一列变成输出的一行,原来从上到下的字段顺序,变成输出行中从左到右的顺序。

原文件有多少列,结果就有多少行;每个输出行又包含原文件的全部行对应的字段。这里按字段转置,不是把文本按固定字符宽度切开,字段长度可以不同。

解法:awk 按列累积

核心思路

[!blue]

awk 默认把每一行作为一条记录,NR 是记录号,NF 是当前行的字段数量,$i 表示当前行第 i 个字段。利用这些内建信息,可以逐行读取,同时为各列分别积累输出。

用 transposed[i] 保存第 i 列已经读到的字段。处理完前 r 行后,这个字符串恰好包含前 r 行的第 i 个字段,并保持输入顺序;读取下一行时,只需把新的同列字段接到末尾,就能继续维持这个对应关系。

第一行直接赋值,后续行才在已有内容与当前字段之间追加 OFS。OFS 默认是单个空格,这样字段之间有分隔,输出行开头又不会多出空格。

在第一行保存 columns = NF,文件读完后进入 END,按照列号 1..columns 依次打印累积字符串。不能用关联数组的任意遍历顺序替代列号顺序,否则会把原列的位置打乱。空文件没有触发首行初始化,默认零列,结束阶段不会输出内容。

解题步骤

  1. 读取第一行时,将字段数保存为 columns。
  2. 对每一行按列号访问 $i。第一行初始化该列字符串,其余行追加分隔空格与新字段。
  3. 文件读取完后,在 END 中从第 1 列依次打印到第 columns 列。
  4. 每打印一个累积字符串就得到一行转置结果,全部列输出后结束。

代码实现

awk '
NR == 1 {
    columns = NF
}
{
    for (i = 1; i <= columns; i++) {
        if (NR == 1) {
            transposed[i] = $i
        } else {
            transposed[i] = transposed[i] OFS $i
        }
    }
}
END {
    for (i = 1; i <= columns; i++) {
        print transposed[i]
    }
}
' file.txt

复杂度分析

设文件有 R 行、C 列,总文本长度为 N。

  • 时间复杂度:字段访问次数为 $O(RC)$;当前实现每次追加都会构造更长的累积字符串,计入复制成本时最坏为 $O(RN)$。字段长度固定时,最坏可写为 $O(CR^2)$。
  • 空间复杂度:$O(N)$,当前实现保存各列的完整输出内容,待文件读完后按列打印。

关键点总结

[!green]

  • 转置只交换行列角色,原列中字段的先后顺序保持不变。
  • $i 读取当前行字段,transposed[i] 保存对应输出行,两者配合完成按列积累。
  • 首行直接赋值,后续才加分隔符,避免前导空格。
  • 输出循环以原列数为界,并显式按数值列号递增。

易错点总结

[!yellow]

  • 用 NR 控制输出行数,混淆了原行数和转置后的行数;转置后应按原列数输出。
  • 所有行都先拼接 OFS,会让每个输出行前面多一个空格。
  • 用 for (i in transposed) 打印,关联数组没有保证列号递增顺序。
  • 把字段读取写成普通变量 i,拿到的是下标本身;动态读取字段应使用 $i。
  • 按固定字符位置切列,无法正确处理长度不同的字段。
  • 只按扫描字段的次数声称整体严格线性,会忽略累积字符串反复复制的成本。

相似题目

题目 难度 关联与区别
867. 转置矩阵 简单 转置关系相同,本题从文本逐行读入,用列缓冲生成输出而非直接访问二维数组。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/71495822
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!