题目:
将字符串 “PAYPALISHIRING” 以Z字形排列成给定的行数:
P A H N
A P L S I I G
Y I R
之后从左往右,逐行读取字符:”PAHNAPLSIIGYIR”
实现一个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = “PAYPALISHIRING”, numRows = 3输出: “PAHNAPLSIIGYIR”
示例 2:
输入: s = “PAYPALISHIRING”, numRows = 4输出: “PINALSIGYAHRPI”解释:
P I N
A L S I G
Y A H R
P I
这个题其实没有什么弯弯绕,解题难度集中在了如何找到一个合理的规律来说明这个Z字形图案。
为了方便理解,这里我画了两个图。图上面的数字代表每个字符在字符串s中的下标。
根据以上两图不难看出,每个Z字形可以作为一个区域(也可称之为一个周期),这里我用红色框标出,那么我们找一找这相邻区域之间存在什么样的规律。
- 相邻两块之间,首行和尾行的数相差:numRows+numRows-2(这个2是指首行和尾行这2行),也就是2*numRows-2;
- 除首行和尾行外,其他的行在相邻两块之间会多一个数(也可以说,每个周期,除了首尾两行,其他行都有两个数,而首尾两行只有一个),比如第二张图,1和7之间有个5,2和8之间有个4。
- 每块第一列的值的下标为(j-1)*(2*numRows-2)+i,其他列的的值坐标为j*(2*numRows-2)-i,i代表第几行,j代表第几块。
根据以上我们找到的规律,就可以很轻松解决了。
两层循环,第一层循环行数,第二层循环块数。子循环中根据上面的公式往一个字符串或者数组中塞值,要注意的是,首尾两行和其他行有区别,当不是首尾两行时,要记得把规律2中提到的两块之间的那个数塞进去。循环中注意判断需要操作的字符的下标是否超出了字符串的最大长度s.length();
代码如下:
class Solution {
public String convert(String s, int numRows) {
if(numRows < 2){return s;}
StringBuilder result = new StringBuilder();
int n = s.length(),rule = 2*numRows-2;
for(int i=0;i<numRows;i++){
for(int j=0;j+i<n;j+=rule){
result.append(s.charAt(j+i));
if(i!=0&&i!=numRows-1&&j+rule-i<n){
result.append(s.charAt(j+rule-i));
}
}
}
return result.toString();
}
}
我也没看大佬们用到了什么方法,找这个的规律已经找的我精神恍惚了。。。