[leetcode] 6. Z 字形变换

文章目录

  • 题目描述
  • 解题方法
    • 方法一:模拟压缩矩阵
      • java代码
    • 方法二:数学构造
      • java代码

题目描述

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

解题方法

方法一:模拟压缩矩阵

我们可以创建一个矩阵,在矩阵上按z字形填写字符串。但若我们设置m ∗ * n阶矩阵(m代表numRows行,n代表字符串长度),则无疑会浪费很多空间,因为有的位置没有填写字符。可以看出我们的输出是按行输出字符,且空字符不输出,所以我们在矩阵每一行添加字符时,可以直接添加到该行的现有字符串后面,从而形成一个压缩矩阵。最后输出答案时,只需按行读取字符。这样就节省了存储空间和遍历时间。

下面可以结合代码看一下具体实现。设r为当前行号(从数组下标0开始),transformFlag为遍历方向标识,当transformFlag为false,r向下遍历;当transformFlag为true,r向上遍历。当r遍历到第0行时,transformFlag变为false,r由向上遍历改为向下遍历;当r遍历到第numRows - 1行时,transformFlag变为true,r由向下遍历改为向上遍历。同时每遍历到某一行,就把当前字符加到该行所在的字符串末尾。

java代码

public String convert(String s, int numRows) {
    if (numRows == 1) {
        return s;
    }
    StringBuilder[] mat = new StringBuilder[Math.min(s.length(), numRows)];
    for (int i = 0; i < mat.length; i++) {
        mat[i] = new StringBuilder();
    }
    int r = 0;
    //代表r的遍历方向,false代表r向下遍历,true代表r向上遍历
    boolean transformFlag = false;
    for (int i = 0; i < s.length(); i++) {
        if (r == 0) {
            transformFlag = false;
        } else if (r == mat.length - 1) {
            transformFlag = true;
        }
        if (!transformFlag) {
            mat[r++].append(s.charAt(i));
        } else {
            mat[r--].append(s.charAt(i));
        }
    }
    StringBuilder res = new StringBuilder();
    for (int i = 0; i < mat.length; i++) {
        res.append(mat[i]);
    }
    return res.toString();
}

时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( N ) O(N) O(N)

方法二:数学构造

[leetcode] 6. Z 字形变换_第1张图片
如上图所示,以红圈圈出的部分为一个z字变换的周期,可以看出z字变换的周期长度为length = (numRows - 1) ∗ * 2。

以下部分结合代码进行理解。设i为当前遍历的行数(从0开始),j为当前行数遍历的字符位置,当i = 0或i = numRows - 1时,j的下一个字符位置即为j += length;否则,每个周期j要遍历的字符分两部分,第一次先将当前j位置的字符加到结果字符串末尾,然后j = j + (numRows - (i + 1)) ∗ * 2,第二次也先将当前j位置的字符加到结果字符串末尾,然后j = j + i ∗ * 2。

java代码

public String convert(String s, int numRows) {
    if (numRows == 1) {
        return s;
    }
    char[] c = new char[s.length()];
    //一次z字遍历的长度
    int length = (numRows - 1) * 2;
    int index = 0;
    for (int i = 0; i < numRows; i++) {
        if (i == 0 || i == numRows - 1) {
            for (int j = i; j < s.length(); j += length) {
                c[index++] = s.charAt(j);
            }
        } else {
            int j = i;
            //false代表加前半截的字符,true代表加后半截的字符
            boolean flag = false;
            while (j < s.length()) {
                c[index++] = s.charAt(j);
                if (!flag) {
                    flag = true;
                    j = j + (numRows - (i + 1)) * 2;
                } else {
                    flag = false;
                    j = j + i * 2;
                }
            }
        }
    }
    return new String(c);
}

时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)


  • 个人公众号
    [leetcode] 6. Z 字形变换_第2张图片
  • 个人小游戏
    个人小游戏

你可能感兴趣的:(leetcode,算法,java,数据结构)