LeetCode6 Z字形变换 ZigZag Conversion

10 篇文章 0 订阅
10 篇文章 0 订阅

LeetCode6 Z字形变换 ZigZag Conversion

题目描述

题目地址:https://leetcode-cn.com/problems/zigzag-conversion/

题目难度:中等

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串

示例

示例1:
输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
示例2:
输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"

分析

通过对几个示例的分析,我发现一个规律,就是每隔2 * numRows - 2,会完成一个周期,通过这个周期可以很容易的找到每一个点所在的列数,按照行列进行遍历,即可得出某一行某一列的字符,最后按照先行后列的顺序拼接即可。

解法1:

public String convert(String s, int numRows) {
    int length = s.length();
    if (length <= numRows || numRows == 1) {
        return s;
    }
    int x = length / (2 * numRows - 2);
    int y = length % (2 * numRows - 2);
    int numCols = x * (numRows - 1) + (y < numRows ? 1 : y % (numRows - 1));
    Character[][] character = new Character[numRows][numCols];
    StringBuffer newString = new StringBuffer();
    int k = 0;
    for (int j = 0; j < numCols; j++) {
        for (int i = 0; i < numRows; i++) {
            if (j % (numRows - 1) == 0 && k < length) {
                character[i][j] = s.charAt(k++);
            } else {
                if (i == numRows - j % (numRows - 1) - 1 && k < length) {
                    character[i][j] = s.charAt(k++);
                }
            }
        }
    }
    for (int i = 0; i < numRows; i++) {
        for (int j = 0; j < numCols; j++) {
            if (character[i][j] != null){
                newString = newString.append(character[i][j]);
            }
        }
    }
    return newString.toString();
}

耗时:106ms 战胜13.78%的提交记录,这个主要是遍历了两次,时间复杂度为O(n^2)

官方解答1:按行访问

思路:按照与逐行读取 Z 字形图案相同的顺序访问字符串

public String convert1(String s, int numRows) {
    int length = s.length();
    if (length <= numRows || numRows == 1) {
        return s;
    }
    int curr = 2 * numRows - 2;
    StringBuffer newString = new StringBuffer();
    for (int i = 0; i < numRows; i++) {
        for (int j = 0; j + i < length; j += curr) {
            newString.append(s.charAt(j + i));
            if (i != 0 && i != numRows - 1 && j + curr - i < length) {
                newString.append(s.charAt(j + curr - i));
            }
        }
    }

    return newString.toString();
}

耗时:14ms 时间复杂度 O(n)

和上边我自己写的方法对比,发现官方给出的解答少了一步赋值的过程,也就是他提前找到了某行某列的值在字符串中的位置,然后直接进行的拼接。另外就是他第二层的遍历是按照周期来进行的,第一个值找到后,之后值的位置加上周期即可,非常巧妙。

官方解答2:按行排序

思路:通过从左向右迭代字符串,我们可以轻松地确定字符位于 Z 字形图案中的哪一行

public String convert2(String s, int numRows) {
    if (numRows == 1) {
        return s;
    }
    List<StringBuilder> rows = new ArrayList<>();
    for (int i = 0; i < Math.min(numRows, s.length()); i++) {
        rows.add(new StringBuilder());
    }
    int curRow = 0;
    boolean goingDown = false;
    for (char c : s.toCharArray()) {
        rows.get(curRow).append(c);
        if (curRow == 0 || curRow == numRows - 1) {
            goingDown = !goingDown;
        }
        curRow += goingDown ? 1 : -1;
    }
    StringBuilder ret = new StringBuilder();
    for (StringBuilder row : rows) {
        ret.append(row);
    }
    return ret.toString();
}

耗时:12ms 时间复杂度:O(n)

可以非常便捷的获得当前字符的行数,然后创建行字符串数组,将每一行的按照从先到后拼接即可,这个方法完全换了一种思路,使得解答起来效果更加鲜明。

相似题目

后续添加

总结

这类型题主要还是要先找规律,然后根据一定的规律,删繁就简找到合适的方法进行解答即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值