LeetCode题练习与总结:Z 字形变换

221 篇文章 0 订阅
134 篇文章 0 订阅

一、题目描述

将一个给定字符串 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

二、解题思路

  1. 初始化:首先,我们需要确定是否需要进行 Z 字形排列。如果 numRows 等于 1 或者字符串长度小于等于 numRows,那么直接返回原字符串,因为这种情况下不需要进行任何变换。

  2. 创建辅助数组:创建一个二维数组(或列表的列表),其大小为 numRows,用于存储每一行的字符。这个数组的每一行将代表 Z 字形排列中的一行。

  3. 填充辅助数组:遍历输入字符串 s,根据当前的行数和 Z 字形排列的规律,将字符填充到辅助数组的相应位置。在 Z 字形排列中,第一行和最后一行的字符是直接从上到下或从下到上填充的。中间的行则需要交替填充,即先从左到右,然后从右到左。

  4. 构建结果字符串:在填充完辅助数组后,我们需要将每一行的字符连接起来,形成最终的 Z 字形排列字符串。这可以通过遍历辅助数组的每一行,并将它们按顺序连接起来实现。

  5. 返回结果:最后,返回构建好的 Z 字形排列字符串。

三、具体代码

class Solution {

    public String convert(String s, int numRows) {
        if (numRows == 1) {
            return s;
        }

        StringBuilder result = new StringBuilder();
        int n = s.length();
        char[][] rows = new char[numRows][];
        for (int i = 0; i < numRows; i++) {
            rows[i] = new char[n];
        }

        int curRow = 0;
        boolean goingDown = false;

        for (int i = 0; i < n; i++) {
            rows[curRow][i] = s.charAt(i);
            if (curRow == 0) {
                goingDown = true;
            } else if (curRow == numRows - 1) {
                goingDown = false;
            }

            if (goingDown) {
                curRow++;
            } else {
                curRow--;
            }
        }

        for (int i = 0; i < numRows; i++) {
            for (int j = 0; j < n; j++) {
                if (rows[i][j] != 0) {
                    result.append(rows[i][j]);
                }
            }
        }

        return result.toString();
    }
}

四、时间复杂度和空间复杂度

代码的时间复杂度是 O(n),空间复杂度是 O(n)

1. 时间复杂度
  • 首先,我们需要遍历整个字符串 s,这需要 O(n) 的时间,其中 n 是字符串的长度。
  • 然后,我们需要填充二维数组 rows,这个过程中,每个字符都会被放置到数组中的一个位置,这同样需要 O(n) 的时间。
  • 最后,我们需要将二维数组中的字符连接成一个新的字符串,这涉及到遍历每一行,这需要 O(n) 的时间。

由于这些操作都是线性的,并且它们都是独立的,所以总的时间复杂度是 O(n) + O(n) + O(n) = O(n)

2. 空间复杂度
  • 我们创建了一个大小为 numRows 的二维数组 rows,每个元素是一个长度为 n 的字符数组。这需要 O(numRows * n) 的空间。
  • 我们还有一个 StringBuilder 对象 result,它在最坏的情况下可能需要存储整个字符串,所以需要 O(n) 的空间。

由于 numRows 是一个常数(在这个问题中,它不会随着输入的增长而增长),所以空间复杂度可以简化为 O(n)

五、总结知识点

  1. 条件判断:使用 if 语句来判断 numRows 的值,以决定是否需要进行 Z 字形变换。

  2. 循环控制:使用 for 循环来遍历字符串 s 和填充二维数组 rows

  3. 数组操作:创建二维数组 rows 并初始化,以及在循环中对数组进行读写操作。

  4. 布尔逻辑:使用布尔变量 goingDown 来控制 curRow 的增减,实现 Z 字形排列的上下移动。

  5. 字符串构建:使用 StringBuilder 类来构建最终的字符串结果,这是一个比使用 String 类更高效的字符串处理方式,尤其是在需要多次修改字符串内容时。

  6. 空间复杂度优化:虽然代码中创建了一个大小为 numRows * n 的二维数组,但实际上这个数组并没有被完全使用。在 Z 字形变换中,只有 numRows 行和 n 列中的部分元素会被填充。这个知识点涉及到空间复杂度的优化,可以通过只创建实际需要的行来减少空间消耗。

  7. 时间复杂度分析:理解代码执行过程中的时间消耗,包括遍历字符串、填充数组和构建结果字符串的时间。

  8. 算法效率:这段代码展示了解决特定问题所需的基本算法逻辑,同时也体现了在实际编程中如何权衡时间和空间的效率。

  9. 代码可读性:代码的组织结构清晰,变量命名直观,有助于理解算法的逻辑流程。

  10. 边界条件处理:代码正确处理了当 numRows 为 1 或字符串长度小于等于 numRows 的边界条件,直接返回原字符串。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值