算法42,模拟算法,模拟z字形变换

LeetCode 6. Z 字形变换 · 总结

一、题目在问什么

把字符串 s 按 Z 字形(从上往下、再从下往上斜着回摆)填入 numRows 行,然后按行从左到右逐行读出,返回读出的结果。

复制代码
输入:  s = "PAYPALISHIRING", numRows = 3
P   A   H   N
A P L S I I G
Y   I   R
输出: "PAHNAPLSIIGYIR"     // PAHN + APLSIIG + YIR

关键认知 :这题根本不用真的"画"出 Z 字阵列。它只问"最终读出来的顺序",所以本质是找下标规律,把字符直接按读出顺序收集起来。


二、核心规律:一个周期 cycle

概念 公式 含义
周期长度 cycle = 2 × numRows − 2 一个"竖列向下 + 斜列向上"单元包含的字符数
第 i 行竖列字符 j = i, i+cycle, i+2cycle ... 每行的"骨架",等差出现
第 i 行斜列字符 k = j + cycle − 2i 夹在两个竖列字符之间的那一个

为什么斜列偏移是 cycle − 2i :第 i 行的竖列字符到自己那一行"峰值"还有 numRows−1−i 步,回摆经过 numRows−1−i 步回到同行,两者相加即 2(numRows−1−i) = cycle − 2i

只有中间行有斜列字符​ ------ 首行和末行每个周期只出现一次,这是最容易漏的分支判断。


三、两种解法

① 公式法(推荐,找规律直取)

复制代码
class Solution {
    public String convert(String s, int numRows) {
        if (numRows == 1 || s.length() <= numRows) return s;
        int n = s.length(), cycle = 2 * numRows - 2;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < numRows; i++) {
            for (int j = i; j < n; j += cycle) {
                sb.append(s.charAt(j));                        // 竖列
                int k = j + cycle - 2 * i;                     // 斜列
                if (i != 0 && i != numRows - 1 && k < n) {
                    sb.append(s.charAt(k));
                }
            }
        }
        return sb.toString();
    }
}

② 模拟法(更不容易写错,行数方向法)

复制代码
class Solution {
    public String convert(String s, int numRows) {
        if (numRows == 1) return s;
        StringBuilder[] rows = new StringBuilder[numRows];
        for (int i = 0; i < numRows; i++) rows[i] = new StringBuilder();
        int cur = 0, step = 1;                     // 当前行 + 行进方向
        for (char c : s.toCharArray()) {
            rows[cur].append(c);
            if (cur == 0) step = 1;                // 触顶→向下
            else if (cur == numRows - 1) step = -1;// 触底→向上
            cur += step;
        }
        StringBuilder sb = new StringBuilder();
        for (StringBuilder r : rows) sb.append(r);
        return sb.toString();
    }
}

模拟法用 step 在上下边界翻转方向,天然规避了斜列下标算错的问题,口算不熟时优先用它;公式法更省内存,是面试时更想听到的"找规律"思路。


四、三个必踩的坑

# 触发后果
1 numRows == 1 不特判 cycle = 0j += 0 死循环(本题头号 WA/TLE 原因)
2 斜列写成 s.charAt(j) 输出 PAHNAALLIIGGYIR:字符重复 + 丢字符 + 长度变长
3 漏判 i != 0 && i != numRows−1,或漏 k < n 首尾行被复制 / 越界 StringIndexOutOfBoundsException

验证用例("PAYPALISHIRING", 3)PAHNAPLSIIGYIR("PAYPALISHIRING", 4)PINALSIGYAHRPI("AB", 1)AB("ABC", 2)ACB。上面三个坑会在这几个用例上立刻暴露(已用 3000 组随机用例与真实 Z 字模拟比对,公式法全部一致)。


五、复杂度与迁移价值

  • 时间 O(n):每个字符恰好被访问一次。
  • 空间 O(n):结果串本身;模拟法额外 O(numRows) 行缓冲。
  • 可迁移的思维 :凡是"按某种规则重排再读出"的题(如螺旋矩阵、对角线遍历),先别急着建二维数组模拟,先算周期和下标通项------能推出公式就 O(1) 额外空间,推不出再用方向模拟兜底。

一句话记住:cycle = 2×numRows−2,竖列 j,斜列 j + cycle − 2i,首尾行没有斜列,一行行数时必先判 numRows == 1

相关推荐
朝朝辞暮i2 小时前
C++第一课
开发语言·c++·算法
橘子汽水1682 小时前
Leetcode 208,207实现Trie前缀树,课程表
java·数据结构·算法·leetcode
hanlin032 小时前
刷题笔记:力扣第169题-多数元素
笔记·算法·leetcode
hfywmsj2 小时前
广州餐饮铺位招租数据建模:基于多维评估体系的选址算法设计与实现
人工智能·算法·广州餐饮铺位招租
wabs6662 小时前
关于二叉树【力扣116.填充每个节点的下一个右侧节点指针的思考】
数据结构·c++·算法·leetcode·二叉树·层序遍历
Nil2082 小时前
leetcode 74搜索二维矩阵
算法·leetcode·矩阵
新知图书3 小时前
第 14 章 后训练算法GRPO详解与实战
人工智能·算法
shirsl5 小时前
算法 Day1-数组 / 哈希 + 双指针
python·算法·哈希算法
2601_9677607812 小时前
2026年PDF压缩与页码添加工具技术实测:性能、算法与本地化适配深度对比
算法·pdf