面试经典150题[022]:Z 字形变换(LeetCode 6)

Z 字形变换(LeetCode 6)

题目链接:Z 字形变换(LeetCode 6)

难度:中等

1. 题目描述

给定一个字符串 s 和行数 numRows,按照 Z 字形从上到下、从左到右排列字符串,然后逐行读取生成新字符串。

  • 字符串长度 1 <= s.length <= 1000,由英文字母(大小写)、',' 和 '.' 组成。
  • 行数 1 <= numRows <= 1000

示例:

复制代码
输入: s = "PAYPALISHIRING", numRows = 3
输出: "PAHNAPLSIIGYIR"
解释:
P   A   H   N
A P L S I I G
Y   I   R

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

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

2. 问题分析

2.1 规律

  • Z 字形排列是一个周期性模式:
    • 每个周期包含 numRows 个字符向下排列,再斜向上排列到第一行。
    • 周期长度为 2 * numRows - 2(向下 numRows 步,向上 numRows - 2 步)。
    • 特殊情况:
      • numRows = 1 时,直接返回原字符串。
      • numRows = 2 时,周期为 2,交替填充两行。
  • 最终输出需要按行读取,行内字符按顺序拼接。
  • 核心问题:如何确定每个字符在 Z 字形中的位置,并按行输出?

2.2 解法思路

方法 1:按行分配(直观模拟)
  • 模拟 Z 字形排列的过程:
    • 遍历字符串 s,按照 Z 字形的路径分配字符到对应行。
    • 使用一个数组(或字符串列表)存储每行的字符。
    • 跟踪当前行和移动方向(向下或向上)。
    • 最后按行拼接结果。
  • 优点:直观,易于理解;空间复杂度较高。
方法 2:按行访问(数学规律)
  • 直接计算每个字符在 Z 字形中的行号,优化空间复杂度。
  • 每个周期的字符位置有规律:
    • i 行的字符索引可以通过周期公式计算。
    • 第一行和最后行的字符索引间隔为 2 * numRows - 2
    • 中间行的字符有两个来源:周期内的向下和斜向上。
    • 向下的字符坐标:当前周期起始点+当前行号。
    • 斜向上的字符坐标:下一个周期的起始点-当前行号。
  • 优点:空间复杂度 O(1),仅需输出字符串的空间。
  • 本题采用 方法 2,因为它更高效且空间复杂度低。

2.3 示例

s = "PAYPALISHIRING", numRows = 4 为例:

复制代码
P     I    N
A   L S  I G
Y A   H R
P     I
  • 周期长度 = 2 * numRows - 2 = 6
  • 第 0 行:P (0), I (6), N (12) → 索引间隔 6。
  • 第 1 行:A (1), L (4), S (7), I (10) → 索引规律为周期内和周期间。
  • 第 2 行:Y (2), A (3), H (8), R (9)。
  • 第 3 行:P (5), I (11)。
  • 按行拼接:PINALSIGYAHRPI

3. 代码实现

Python

python 复制代码
class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1 or numRows >= len(s):
            return s
        
        result = []
        n = len(s)
        cycle = 2 * numRows - 2
        
        for i in range(numRows):
            for j in range(0, n, cycle):
                # 第一行和最后行
                if i == 0 or i == numRows - 1:
                    if j + i < n:
                        result.append(s[j + i])
                # 中间行
                else:
                    # 周期内的字符
                    if j + i < n:
                        result.append(s[j + i])
                    # 周期间的字符(斜向上)
                    if j + cycle - i < n:
                        result.append(s[j + cycle - i])
        
        return ''.join(result)

C++

cpp 复制代码
class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows == 1 || numRows >= s.length()) {
            return s;
        }
        
        string result;
        int n = s.length();
        int cycle = 2 * numRows - 2;
        
        for (int i = 0; i < numRows; ++i) {
            for (int j = 0; j < n; j += cycle) {
                // 第一行和最后行
                if (i == 0 || i == numRows - 1) {
                    if (j + i < n) {
                        result += s[j + i];
                    }
                }
                // 中间行
                else {
                    // 周期内的字符
                    if (j + i < n) {
                        result += s[j + i];
                    }
                    // 周期间的字符(斜向上)
                    if (j + cycle - i < n) {
                        result += s[j + cycle - i];
                    }
                }
            }
        }
        
        return result;
    }
};

4. 复杂度分析

  • 时间复杂度 :O(n),其中 n 是字符串 s 的长度。每个字符最多被访问一次。
  • 空间复杂度
    • Python:O(n),用于存储结果字符串(result 列表)。
    • C++:O(1),不计输出字符串的空间(result 直接追加)。

5. 总结

  • Z 字形变换 :核心是理解周期性规律,周期长度为 2 * numRows - 2
  • 按行访问方法利用数学规律,高效且空间优化。
  • 特殊情况(numRows = 1numRows >= n)需提前处理。
  • 可扩展到变体问题,如动态行数或不同排列方式。
相关推荐
ShineSpark7 小时前
C++面试11——指针与引用
c++·面试
测试老哥9 小时前
Python+selenium自动化生成测试报告
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
ThreeAu.9 小时前
2025年Web自动化测试与Selenium面试题收集:从基础到进阶的全方位解析
自动化测试·软件测试·selenium·测试工具·面试·web测试·测试开发工程师
在未来等你9 小时前
Elasticsearch面试精讲 Day 20:集群监控与性能评估
大数据·分布式·elasticsearch·搜索引擎·面试
2351610 小时前
【LeetCode】3. 无重复字符的最长子串
java·后端·算法·leetcode·职场和发展
零雲11 小时前
java面试:可以讲一讲sychronized和ReentrantLock的异同点吗
java·开发语言·面试
crystal_pin11 小时前
前端流式解析chunk数据思路
面试
甜瓜看代码11 小时前
面试---h5秒开优化
面试
微笑尅乐11 小时前
神奇的位运算——力扣136.只出现一次的数字
java·算法·leetcode·职场和发展
自信的小螺丝钉12 小时前
Leetcode 155. 最小栈 辅助栈
leetcode·