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)
可以非常便捷的获得当前字符的行数,然后创建行字符串数组,将每一行的按照从先到后拼接即可,这个方法完全换了一种思路,使得解答起来效果更加鲜明。
相似题目
后续添加
总结
这类型题主要还是要先找规律,然后根据一定的规律,删繁就简找到合适的方法进行解答即可。