题目有点唬人,当然要的就是这个效果,标题党一把。从现在开始做100道leetcode题目,为了起到比较好的督促作用,就从100倒数开始。言归正传,今天开始这次的题目吧。
题目名称
Z字型排列
描述
将一个字符串根据给定的行数,从上往下,从左到又开始z字型排列,输出最终的字符串。
举例输入LEETCODEISHIRING
,行数为3,则结果为:
L C I R
E T O E S I I G
E D H N
输出为LCIRETOESIIGEDHN
。
当行数为4,输出为LDREOEIIECIHNTSG
,结果:
L D R
E O E I I
E C I H N
T S G
解题思路
刚开始想从行开始,比如每一行隔几个空格,但是考虑到字符是竖着按列来打印的,中间空格和字符位置关系没有找到,随之放弃;再试着把所有字符放到一个矩阵里,发现对二维数据操作比较复杂,也放弃了这种思路。
最终,考虑到是按列排列字符(可见图片方向),而且每列可以分成开头的空格,结尾的空格,而且是比较有规律的。如上在4行的时候,开头空格是0 2 1 0 2 1 0 ... ...
。因此,将每列存到一个Map中,列号为key,每个里边保存一列的结果,填充前后空格,字符位置从序号累计索引取到并赋值。

其中要注意的是几个边界条件。在最后,通过遍历map让,用行数来索引map保存的列字符串,最终打印出结果,代码是accepted的。分析来看,如果字符串长度m,行数为n,复杂度大致在O(m*n)
。
代码
public String convert(String s, int numRows) {
if(numRows <= 1){
return s;
}
int l = 0;
Map<Integer, StringBuilder> lineMap = new HashMap<>();
int idx = 0;
while (idx < s.length()) {
//存储每行
StringBuilder builder = new StringBuilder();
int i = 0;
while (i<numRows && idx<s.length()) {
//开头空格
int space = l % (numRows -1);
for (int j = 0; j < numRows - space - 1 && space != 0; j++) {
builder.append(" ");
i++;
}
builder.append(s.charAt(idx++));
i++;
for (int j = 0; j < space; j++) {
builder.append(" ");
i++;
}
}
lineMap.put(l++, builder);
}
//最终打印
StringBuilder builder = new StringBuilder();
for (int i = 0; i < numRows; i++) {
for(StringBuilder b: lineMap.values()){
if(null != b && b.length() > i && b.toString().charAt(i)!= ' '){
builder.append(b.charAt(i));
}
}
}
return builder.toString();
}
总结
总体来看,实现不算简洁,花的时间也较多,但是是自己的思路来完成的,希望通过多多练习能提高熟练度。
以上,感谢阅读。
网友评论