【Day 4】公开打卡第4天 | LeetCode 6. Z 字形变换 + 方向标志法模拟

0 阅读3分钟

【Day 4】公开打卡第4天 | LeetCode 6. Z 字形变换 + 方向标志法模拟

正文结构

  1. 今日打卡宣言 Day 4,坚持第4天了!把这道经典 Z 字形题手写了一遍。连续4天没断,感觉刷题的手感在慢慢回来。继续冲,欢迎监督!

  2. LeetCode 部分

  3. Z 字形变换

已解答

中等

相关标签

premium lock icon相关企业

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

 

示例 1:

输入: s = "PAYPALISHIRING", numRows = 3
输出: "PAHNAPLSIIGYIR"

示例 2:

输入: s = "PAYPALISHIRING", numRows = 4
输出: "PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I

示例 3:

输入: s = "A", numRows = 1
输出: "A"

 

提示:

  • 1 <= s.length <= 1000

  • s 由英文字母(小写和大写)、',' 和 '.' 组成

  • 1 <= numRows <= 1000

    • 题目链接:leetcode.cn/problems/zi… (或英文:leetcode.com/problems/zi…
    • 难度:中等
    • 时间复杂度:O(n),n = s.length()
    • 核心思路(简短): 模拟 Z 字形书写过程:从上往下写到第 numRows 行后,转向上写到第 1 行,再向下……用一个 flag(或 direction)来控制当前行是 +1 还是 -1。每个字符追加到对应行的字符串,最后拼接所有行。
    • 代码(你提供的 C++ 版本,稍加注释,更易懂):

C++

class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows < 2) return s;  // 1行或0行直接返回原串
        
        vector<string> rows(numRows);  // 每行一个字符串
        int i = 0;                     // 当前行索引
        int flag = -1;                 // 方向:-1 向上,+1 向下
        
        for (char c : s) {
            rows[i] += c;              // 当前字符追加到当前行
            
            // 到达顶部或底部时,翻转方向
            if (i == 0 || i == numRows - 1) {
                flag = -flag;
            }
            
            i += flag;                 // 移动到下一行
        }
        
        string res;
        for (auto& str : rows) {
            res += str;                // 按行拼接
        }
        return res;
    }
};
  • Go 版本(如果你想双语放一个,方便读者):

Go

func convert(s string, numRows int) string {
    if numRows < 2 || len(s) <= numRows {
        return s
    }
    
    rows := make([]string, numRows)
    i, flag := 0, -1
    
    for _, c := range s {
        rows[i] += string(c)
        
        if i == 0 || i == numRows-1 {
            flag = -flag
        }
        i += flag
    }
    
    var res strings.Builder
    for _, row := range rows {
        res.WriteString(row)
    }
    return res.String()
}
  • 易错点/优化点:

    1. numRows == 1 时直接返回 s(边界)。
    2. flag 初始 -1 是巧妙的(从第0行开始向下时先不翻转)。
    3. i += flag 后不会越界,因为在边界时刚好翻转。
    4. 面试追问:不用额外空间 O(1) 怎么做?(数学公式直接计算每个字符位置,但代码更复杂,今天这个模拟法最直观)。 示例:s = "PAYPALISHIRING", numRows = 3 → "PAHNAPLSIIGYIR"
  1. 知识点部分(今天配 C++ vector 使用 & strings.Builder 在 Go 中的优势) C++ vector 拼接 & Go strings.Builder 高效拼接

    • C++:vector 每行独立追加,最后 for 循环 +=(现代 C++ string 优化较好,但仍可能有多次分配)。

    • Go:直接 += 会产生很多临时 string(因为 string 不可变),推荐用 strings.Builder:

      • WriteString 无需中间拷贝,性能更好。
    • 面试常问:大量字符串拼接怎么优化?(C++ reserve 容量;Go 用 Builder 或 bytes.Buffer)。

    • 这题 n ≤ 1000,影响不大,但养成好习惯。

  2. 今日感悟 这道题以前觉得“找规律难”,今天用方向标志法写完才发现其实很简单——就是模拟过程 + 边界翻转。公开打卡让我必须把代码跑通、边界考虑全,不然发出去没底气。Day 4 了,坚持的感觉真不错,离目标又近了一点!

  3. 结束语 明天见! 欢迎评论区:① 你的 Z 字形写法(有数学公式解吗?) ② 代码哪里还能改进 ③ 你刷这题花了多久 #程序员打卡 #LeetCode #Z字形变换 #C++ #Go语言