Leetcode-6. Z 字形变换

152 阅读2分钟

题目

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

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/zi…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

其实这道题目的示例所给出的二维数组有一定的迷惑性,很容易让人想到的方法是使用二维数组控制下标填放字符到对应的位置,其中要考虑下一个位置是否要斜着放,然后按照行再遍历获取结果。但是下标的控制需要给很大功夫,导致增加了编码的困难。其实并不用考虑斜着放,而是将每一行看成一个队列,往队列尾部插入数据即可,这样插入方便而且不用考虑空数据。

更好的方法是使用链表数组,然后按照从上到下,再从下到上的顺序放置对应的值,最后遍历链表数组,每次拿到一行数据进行拼接,示例图如下所示:

image.png

代码

public String convert(String s, int numRows) {
    // 只有一行的话就直接返回
    if (numRows == 1) {
        return s;
    }
    // 构造链表数组并初始化
    List<StringBuffer> data = new ArrayList<>();
    for (int i = 0; i < Math.min(s.length(), numRows); i++) {
        data.add(new StringBuffer());
    }
    // 相关临时变量
    boolean isGoingDown = false;
    int currIndex = 0;
    // 遍历整个参数
    for (char c : s.toCharArray()) {
        // 添加当前字符
        data.get(currIndex).append(c);
        // 判断下标走向
        if (currIndex == 0 || currIndex == numRows - 1) {
            isGoingDown = !isGoingDown;
        }
        // 计算下一次遍历的下标
        currIndex += isGoingDown ? 1 : -1;
    }

    // 将数据横向整合
    StringBuilder sbRet = new StringBuilder();
    data.stream().forEach(row->{
        sbRet.append(row);
    });
    return sbRet.toString();
}

测试用例

public class Solution_Test_6 {
    Solution_6 solution_6 = new Solution_6();
    @Test
    public void test1() {
        String s = "PAYPALISHIRING";
        Integer numRows = 3;
        String convert = solution_6.convert(s, numRows);
        assertEquals(convert, "PAHNAPLSIIGYIR");
    }

    @Test
    public void test2() {
        String s = "PAYPALISHIRING";
        Integer numRows = 4;
        String convert = solution_6.convert(s, numRows);
        assertEquals(convert, "PINALSIGYAHRPI");
    }

    @Test
    public void test3() {
        String s = "A";
        Integer numRows = 1;
        String convert = solution_6.convert(s, numRows);
        assertEquals(convert, "A");
    }

    @Test
    public void test4() {
        String s = "AB";
        Integer numRows = 1;
        String convert = solution_6.convert(s, numRows);
        assertEquals(convert, "AB");
    }
}