ZigZag Conversion
The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: “PAHNAPLSIIGYIR”
Write the code that will take a string and make this conversion given a number of rows:
string convert(string text, int nRows);
convert(“PAYPALISHIRING”, 3) should return “PAHNAPLSIIGYIR”.
Solution1
- 这种解法没什么诀窍,无非是注意一些边界条件。我在这里用一个StringBuffer数组来模拟每一行,然后针对原始字符串进行遍历,在StringBuffer数组上去模拟之字形走路线,这里需要注意的是,每到之字形的末尾和之字形的头部的时候,便需要转向。这里用一个flag来标志每次转向的方向,代码如下:
public class Solution {
public String convert(String s, int numRows) {
if(numRows<=1) return s;
StringBuffer[] sbs = new StringBuffer[numRows];
for(int i=0;i<numRows;i++) sbs[i] = new StringBuffer();//注意必须在创建StringBuffer数组后针对每一个去new一个出来,不然初始值都是null
boolean flag = false;
for(int i=0,j=0;i<s.length();i++){
char c = s.charAt(i);
sbs[j].append(c);
if(!flag&&j==numRows-1) flag = true;//到达末尾了,从后往前转向
if(flag&&j==0) flag = false;//到达头部了,从头往后转向
if(flag) j--;
else j++;
}
StringBuffer result = new StringBuffer();
for(StringBuffer sb:sbs) result.append(sb);
return result.toString();
}
}
Solution2
- 解法1用到了一个StringBuffer数组,实际上这个数组是多余的,完全不用先去得到每行的字符串后再最后才去合并成一个字符串。可以将字符串分割成每一小段,在这每一小段里都可以有一定的规律。代码如下:
if(numRows<=1||s.length()==0) return s;
StringBuffer sb = new StringBuffer();
int step = 2*numRows - 2;//将字符串分割成一段一段
for(int i=0;i<numRows;i++){
if(i==0||i==numRows-1){//当i在首行和末尾行时,直接将相隔step个间隔的字符组成各自行。
for(int j=i;j<s.length();j+=step) sb.append(s.charAt(j));
continue;
}
for(int j=i;j<s.length();j+=step){//注意j+=step,所以也是将原始字符串每相隔step个间隔来进行考虑。
sb.append(s.charAt(j));
if(j+step-2*i<s.length()) sb.append(s.charAt(j+step-2*i));//在每一个step区间段内部,还有另外一个相隔(step-2*i)的一个字符也添加进来。
}
}
return sb.toString();
- 解法2相比解法1的空间使用更加节省,但实际的空间复杂度并没有变。时间复杂度和空间复杂度都为O( N <script type="math/tex" id="MathJax-Element-1">N</script>)