问题
将字符串 "PAYPALISHIRING" 以Z字形排列成给定的行数:(下面这样的形状)
P A H N
A P L S I I G
Y I R
之后按逐行顺序依次排列:"PAHNAPLSIIGYIR"
实现一个将字符串进行指定行数的转换的函数:
string convert(string text, int nRows);
convert("PAYPALISHIRING", 3) 应当返回 "PAHNAPLSIIGYIR" 。
思路
这个问题其实很简单,它只涉及到下标,你只要观察就能看出一个时间复杂度为O(n)的算法的。它是一个个重复的波形,而整个波形都是重复了从0开始到2×row-3这一段的波形,所以现在我暂时先只研究[0,2×row-3]这一段,[0,row-1]是竖直的,[row,2×row-3]是左下右上斜的。其中,第0行的下一个波形的下标与本波形同一行的相邻的下标相减是2×row-2-0=2×row-2。第1行本身波形与本身波形相邻的下标相减是2×row-3-1=2×row-4,下一个波形与本波形的相邻的下标相减是2,这两个差之和是2×row-2。再下一行就是2×row-6和4之和,也是2×row-2。所以问题的解法就出现了,从0到row-1进行遍历,现在正在遍历第i行,它先走了2×row-i×2的步长得到了一个字符,再走一个i×2就到了同一行下一个字符,如此往复地走直到越界为止,这一行就没了。虽然说循环有2层但是实际上却只进行了n步,所以时间复杂度是O(n)。但是对于行数只有1和行数大于等于字符串字符个数的情况,输出的字符串都是原来的字符串,不需要处理,直接输出就好。于是就得到了算法的实现。
使用
package com.company;
public class Main {
public static void main(String[] args) {
// write your code here
String inputString = "PAYPALISHIRING";
String inputString0 = "ABCDE";
System.out.println(Solution.zigzagString0(inputString,4));
}
}
输出
P I N
A L S I G
Y A H R
P I
Process finished with exit code 0
实现
package com.company;
public class Solution {
static public String zigzagString(String sourceString,int rows) {
if (rows < 1 || sourceString == null) {
System.out.println("输入非法");
return "";
}
StringBuilder resultBuilder = new StringBuilder();
for (int counter = 0;counter < rows;counter++) {
if (rows == 1 || rows >= sourceString.length()) {
return sourceString;
} else {
int stepLength = 2 * rows - 2 - 2 * counter;
int counter0 = counter;
while (counter0 < sourceString.length()) {
resultBuilder.append(sourceString.charAt(counter0));
if (stepLength != 2 * rows - 2 && stepLength != 0) {
counter0 += stepLength;
stepLength = 2 * rows - 2 - stepLength;
}
else if (stepLength == 0) {
stepLength = 2 * rows - 2;
counter0 += stepLength;
} else {
counter0 += stepLength;
}
}
}
}
return resultBuilder.toString();
}
/**
* 这么做没什么不同,只不过是把字符串打印成Z字形。
* @param sourceString
* @param rows
* @return
*/
static public String zigzagString0(String sourceString,int rows) {
if (rows < 1 || sourceString == null) {
System.out.println("输入非法");
return "";
}
StringBuilder resultBuilder = new StringBuilder();
for (int counter = 0;counter < rows;counter++) {
if (rows == 1 || rows >= sourceString.length()) {
return sourceString;
} else {
int stepLength = 2 * rows - 2 - 2 * counter;
int counter0 = counter;
for (int counter1 = counter;counter1 < sourceString.length();counter1++) {
if (counter1 == counter0) {
System.out.print(sourceString.charAt(counter1));
if (stepLength != 2 * rows - 2 && stepLength != 0) {
counter0 += stepLength;
stepLength = 2 * rows - 2 - stepLength;
}
else if (stepLength == 0) {
stepLength = 2 * rows - 2;
counter0 += stepLength;
} else {
counter0 += stepLength;
}
} else {
System.out.print(" ");
}
}
System.out.println();
}
}
return resultBuilder.toString();
}
}