📜  Z转换(ZT)(1)

📅  最后修改于: 2023-12-03 15:06:08.528000             🧑  作者: Mango

Z字形转换(ZigZag Conversion)

在编程中,Z字形转换指将一个字符串按照“Z”字形排列成给定的行数,然后逐行逐个字符读取。例如,一个字符串 "PAYPALISHIRING",行数为 3,它会被排列成如下的形式:

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

然后按照行读取:"PAHNAPLSIIGYIR"

此主题总结了如何实现Z字形转换。在以下的讨论中,我们将通过一个示例字符串“PAYPALISHIRING”来进行说明。

Ⅰ. 模拟行
思路

大多数人都能独立想出数组模拟的算法,但思考它的时间可能会比单个字符管理者要长。

我们可以使用min(numRows,len(s))个列表来模拟将字符添加到合适的行中。从左到右迭代字符串s,将空余的字符串填入我们的字符串列表中的合适行中。每当行达到最后一行或第一行时,子串就应该反转。

我们可以使用一个flag变量来反转方向,当我们移动到第一行或最后一行时,我们将flag取反。

代码实现
def convert(s: str, numRows: int) -> str:
    if numRows == 1 or numRows >= len(s):
        return s
    res = ["" for _ in range(numRows)]
    index, flag = 0, -1
    for i in s:
        res[index] += i
        if index == 0 or index == numRows - 1:
            flag = -flag
        index += flag
    return "".join(res)
时间复杂度

当行数为numRows时,字符串s的遍历时间复杂度为O(N),这里的N是字符串长度。添加到列表中的时间复杂度为O(1),所以最终的时间复杂度为 O(N)。

空间复杂度

使用了min(numRows,len(s))个字符串列表,所以空间复杂度为O(min(numRows,len(s)))。

Ⅱ. 按行排序
思路

按照与读取顺序相同的顺序访问字符串。首先访问行0中的所有字符,然后访问行1,然后行2,依此类推...对于所有整数k,

  • 行0中的字符位于索引k(2*numRows−2)处;
  • 行numRows−1中的字符位于索引k(2*numRows−2)+numRows−1处;
  • 内部行中的字符位于索引k(2numRows−2)+i以及(k+1)(2numRows−2)−i处;
代码实现
def convert(s: str, numRows: int) -> str:
    if numRows == 1 or numRows >= len(s):
        return s
    n = len(s)
    cycle_len = 2 * numRows - 2
    res = []
    for i in range(numRows):
        for j in range(0, n - i, cycle_len):
            res.append(s[j + i])
            if i != 0 and i != numRows - 1 and j + cycle_len - i < n:
                res.append(s[j + cycle_len - i])
    return "".join(res)
时间复杂度

遍历字符串s的时间复杂度为O(N),其中N是字符串长度。在转换中,我们按顺序访问每个字符,将它放入正确的行。因为每个字符正好被访问一次,所以时间复杂度是O(N)。

空间复杂度

除了输出字符串之外,这种方法所需的空间复杂度较小。在生成输出字符串时,我们需要使用O(N)的空间来保存整个字符串。

以上就是Z字形转换的两种解法。在实现时,可以根据实际需要,从中选择一种较为简单或者适合的解法。