题目:
将字符串 "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
解法1:这是一种很笨的方法,一开始一位规律会很难找,所以就想到用这种方法先做出来再说,
class Solution {
public String convert(String s, int numRows) {
if(numRows==1){
return s;
}
StringBuilder str = new StringBuilder();
List<char[]> list = new ArrayList<>(); //存储整个的Z形的所有列
int size = 0,len = s.length();
for(int i = 0;i<len;i++){
char[] chars = new char[numRows]; //存储每一列的数据
int remainder = i%(numRows-1); //计算余数,确定是否是整列
for(int j = remainder==0?0:numRows-1-remainder;j<numRows-remainder;j++){ //如果是整列起点为0,否则为numRows-1-remainder
chars[j] = s.charAt(size++); //把列上的数据填到对应位置
if(size>=len){ //全部遍历完跳出循环
break;
};
}
list.add(chars); //把每一列的数据加入集合
if(size>=len){
break;
};
}
for(int j = 0;j<numRows;j++){ //遍历集合把为默认值的char排除拼接起来
for(int i = 0,length = list.size();i<length;i++){
char[] chars = list.get(i);
if(chars[j]!='\u0000'){
str.append(chars[j]);
}
}
}
return str.toString();
}
}
这里就是把每一列的数据都遍历出来,以char数组的结构存到以list上,然后再通过遍历把不是默认值的字符拼接起来,其实这里如果用二维数组可能效果会好一点,在第二遍历的时候空间复杂度会小一点;
时间复杂度:O(n)
空间复杂度:O(n^2)
解法2:
class Solution {
public String convert(String s, int numRows) {
int length = s.length();
if(length<=1||numRows<=1){ //特殊参数情况处理
return s;
}
StringBuilder str = new StringBuilder();
for(int i = 0;i<numRows;i++){ //一行一行遍历出字符
int num = i;
while(num<length){
str.append(s.charAt(num));
if(i!=0&&i!=numRows-1&&num+2*(numRows-1-i)<length){ //如果不是第一行和最后一行,把单独的一个字符拼接
str.append(s.charAt(num+2*(numRows-1-i)));
}
num += 2*(numRows-1); //一个循环的等差
}
}
return str.toString();
}
}
这个方法直接遍历拼接字符串,因为我们可以找到对应的规律,先不考虑中间空缺的列,每一行对应的数对应的等差为2*(numRows-1);接下来考虑特殊情况,即不在第一行和最后一行的时候,把多余的一个字符加入进来,这里也可以发现规律,如果行数为num,则两个的差值为2*(numRows-1-num);所有直接遍历拼接出字符串,比起第一种解法少了求出每一列的计算。而且空间复杂度也小很多。提交的数据第一个时间为89ms,第二种解法为39ms;
时间复杂度:O(n);
空间复杂度:O(n)