题目描述
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zigzag-conversion
解题思路
将排列后的Z字型字符串存入二维字符型数组中,再按照从上往下从左往右的顺序输出并拼接成字符串。由于Java中char类型的字符数组如果不进行初始化,系统会默认给其赋值Unicode编码为0000(\u0000)的字符。所以在从二维数组输出时注意判断该字符是否为系统中自动赋值的字符。
Java程序
public class Solution {
public String convert(String s, int numRows) {
//如果只有一行,直接输出该字符串
if (numRows == 1)
return s;
else {
//定义二维数组,行数为numRows,由于列数未知,故列数定义为最大值(字符串长度)
char[][] str = new char[numRows][s.length()];
int n = 0;//n用于记录字符串中字符的索引
//当n不等于字符串长度时,说明字符串还未遍历完,否则停止遍历
for (int i = 0; n != s.length(); i++) {
//如果当前列数为第一列或者为满列(该列的每一个位置都需要填满字符)
if (i == 0 || (i % (numRows - 1)) == 0) {
//逐一向该列的所有位置填满字符
for (int j = 0; j < numRows && n != s.length(); j++) {
str[j][i] = s.charAt(n);
n++;
}
} else {
str[numRows - (i % (numRows - 1)) - 1][i] = s.charAt(n);
n++;
}
}
//将二维数组转换为字符串并去掉Unicode编码为0000的字符
String str1 = new String();
for (int i = 0; i < numRows; i++)
for (int j = 0; j < s.length(); j++) {
if (Character.hashCode(str[i][j]) != 0000)
str1 += str[i][j];
}
return str1;
}
}
}
解题要点
POINT 1:如何判断该列是否为满列?
由题目所给示例可以发现,无论字符串的长度和numRows的值为多少,二维字符数组的第一列均为满列。并且,下一次满列所在的列数下标值与所给的numRows值有关,即当前列数索引值i % (numRows - 1)) == 0时,该列为满列。
【注】满列是指如果该列的每一个位置都需要填入字符串中的字符时,称该列为满列。
POINT 2:当该列不是满列时,如何判断该列的那些位置需要填入字符?
根据所给示例可以总结出如下规律:当该列的行下标为numRows - (i % (numRows - 1)) - 1时,该位置(str[numRows - (i % (numRows - 1)) - 1][i])需要填入字符。
【注】i表示当前列数
POINT 3:如何将含有未初始化字符的二维字符数组去掉未初始化字符并转为字符串?
将字符数组转换为字符串的方法有很多,例如toString(),deepToString(),StringBuffer()等方法,但是这些方法输出的字符串以字符数组的形式输出并且去除未初始化字符难度较大。因此,可以以for循环对二维数组进行遍历,如果不是未初始化的字符直接使用字符串连接符“+“进行拼接。