6. Z字形变换 - LeetCode
6. Z字形变换
按列模拟
class Solution {
public String convert(String s, int numRows) {
if (numRows == 1){
return s;
}
int rowMax = Math.min(numRows, s.length());
List<StringBuilder> rows = new ArrayList<>();
for (int i = 0; i < rowMax; i++)
rows.add(new StringBuilder());
int curRow = 0;
int direction = -1;
for (char c : s.toCharArray()) {
rows.get(curRow).append(c);
if (curRow == 0 || curRow == numRows - 1){
direction *= -1;
}
curRow += direction;
}
StringBuilder ans = new StringBuilder();
for (StringBuilder row : rows) ans.append(row);
return ans.toString();
}
}
按题意模拟Z字形的过程,枚举每一行,到头了变方向,按顺序把字符加入对应的行,最后把每一行的字符拼起来。这里注意以下几点:
- StringBuilder:
- 功能类似于StringBuffer,但线程不安全,所以更快。
- 通过append加入字符或字符串
- 通过toString转换为字符串
- List:
- 通过add添加元素
- 通过get获取元素的引用,对象的引用可以改变其中的值
- For-Each:
- 如果只需要取数组或者List中的值,不需要对其修改时,可以使用For-Each循环
- 对String使用时,需要toCharArray转换为字符数组
这里的时间复杂度为O(n),但是最后需要一行一行地拼起来,所以很慢。因此可以想到,把每一行字符在原字符串中的位置之间算出来,这样就可以按顺序添加,而非模拟Z字形再拼接。
计算每行字符在原字符串中的位置
class Solution {
public String convert(String s, int numRows) {
if (numRows == 1){
return s;
}
int n = s.length();
StringBuilder ans = new StringBuilder();
int num = 2 * numRows - 2;
for (int i = 0; i < numRows; i++) {
int del =num - 2 * i;
for (int j = i; j < n; j += num) {
ans.append(s.charAt(j));
if (i != 0 && i != numRows - 1 && j + del < n)
ans.append(s.charAt(j + del));
}
}
return ans.toString();
}
}
可以将一个来回视为一组,除了首行和末行,每组都有两个字符。
显然第i行的第一个字符是原字符串中的第i个字符。之后仅需计算组内两个字符的距离,以及组间的距离即可。
因为是按行数一来一回,所以显然每组的第一个字符之间的距离是2 * numRows - 2。
组内,按照Z字形的规律,第一个字符到第二个字符,显然是从下一组第一个字符往回走2*i。
有了这样的规律,我们一次添加一组的两个字符即可。
这样虽然时间复杂度仍为O(n),中间也略有计算,但总体来说,直接计算出下一个字符的位置,是快于多行拼凑的。

浙公网安备 33010602011771号