刚看到这个题目我是有点懵逼的,看懂题目都花了我好一会功夫。
先来说一下我自己的思路:我看到这个图我就觉得是有规律可循的,是不是能找出每一行元素的下标的通项,然后用个for loop给他们都整出来就好了。在我尝试后,我发现确实是有规律的,第一行和最后一行确实是有通项,但是中间的行没有唯一通项,他们有两个。然后我就陷入了纠结不知道这样做是否可行。再我看完标答的思路之后我发现是和我一样的,也是找规律的,官方给出的规律如下:
下面给出按照这种思路的写的解答:
public String convert(String s, int numRows) {
//方法一 row by row
if(numRows == 1){ //一行的情况
return s;
}else{ //大于一行的情况
StringBuilder str = new StringBuilder();
int n = s.length();
int cycleLen = 2 * numRows - 2; //这个cycleLen很重要,是找规律找出来的,可以自己画图找出这个周期
for(int i = 0; i < numRows; i++){ //此for loop用来控制多少行,可以看到行数就是numRows。如果numRows=5,那么这个for loop就循环5次。具体操作就是依次将每一行的元素append进str中
for(int j = 0; i + j < n; j+= cycleLen){ //此for loop就是将每一行该有的元素都找出来,加入到str中。
str.append(s.charAt(i + j)); //先append竖列上的
if(i != 0 && i!= numRows - 1 && j + cycleLen - i < n){
str.append(s.charAt(j + cycleLen - i)); //再append斜列上的
}
}
}
return str.toString();
}
}
上面这种方法其实是row by row的,依次将每行的元素加入到一个stringbuilder中。先把第一行的都加进去,再把第二行的都加进去。。。直到最后一行。
下面介绍第二种方法,这是discussion中highest votes的答案,我个人觉得非常的好,简单易懂。重要步骤的解释我都写上了注释,可能看起来会有些乱
public String convert(String s, int numRows) {
//方法二 character by character
if(numRows == 1){return s;}
char[] c = s.toCharArray(); //char类型数组,注意这边定义char[], c要小写,有点奇怪,我一直以为要大写
int length = c.length; //注意c.length没有()
StringBuilder[] sb = new StringBuilder[numRows]; //定义一个大小为numRows的stringbuilder类型的数组
for(int i = 0; i< sb.length; i++){
sb[i] = new StringBuilder(); //定义数组中每一个stringbuilder,这样每一个sb就可以单独拿出来使用了。假设numRows=5.那这边就一共5个sb,正好对应5行,每个sb存储相对应行数里的元素
}
//really elegant way! 建议跟着这个循环自己画图走一遍,这个算法就很容易明白了。光看的话很难懂
int i = 0;
while(i < length){
for(int idx = 0; idx < numRows && i < length; idx++){
sb[idx].append(c[i++]); //先垂直方向依次append元素
}
for(int idx = numRows - 2; idx >= 1 && i < length; idx--){
sb[idx].append(c[i++]); //再斜右向上方向依次添加元素。整个过程就是先向下,再斜右向上,再竖直向下,再斜右向上。。。。以此类推
}
}
for(int n =1; n < sb.length; n++){
sb[0].append(sb[n]);
}
return sb[0].toString();
}
总结
- 这题最主要的还是要找到规律,说是string题,其实我觉得更像math题
- 熟悉数组的使用
- 熟悉stringbuilder的使用
- tochararray(),将一个string转换为一个有次序的character squence