将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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);
示例 1:
输入: s = “LEETCODEISHIRING”, numRows = 3
输出: “LCIRETOESIIGEDHN”
示例 2:
输入: s = “LEETCODEISHIRING”, numRows = 4
输出: “LDREOEIIECIHNTSG”
解释:
L D R
E O E I I
E C I H N
T S G
C#语言实现
方法一:二维数组
思路
例如:
L D R
E O E I I
E C I H N
T S G
那么从LEET ,C,O三个为一个周期,这个周期内有6个元素,3个数组,以此类推
public static string Convert(string s, int numRows)
{
if (s.Length <= numRows || numRows == 1) return s;
int cycleNumber = numRows * 2 - 2;//每周期字符个数
int cycleArrayCount = numRows - 1;//每周期数组个数
//总共需要多少数组
int arrayCount = s.Length / cycleNumber * cycleArrayCount;
if (s.Length < cycleNumber)
{
arrayCount = cycleArrayCount - (cycleNumber - s.Length);
}
if (s.Length > cycleNumber && s.Length % cycleNumber != 0)
{
if (s.Length % cycleNumber <= numRows)
++arrayCount;
else
arrayCount += s.Length % cycleNumber % numRows + 1;
}
char[][] array = new char[arrayCount][];
int strIndex = 0;
for (int i = 0; i < arrayCount; i++)
{
array[i] = new char[numRows];
if (i % cycleArrayCount != 0)
array[i][cycleArrayCount - i % cycleArrayCount] = s[strIndex++];
else
{
for (int j = 0; j < numRows; j++)
{
if (strIndex < s.Length)
array[i][j] = s[strIndex++];
}
}
}
List<char> charList = new List<char>();
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j < arrayCount; j++)
{
if (array[j][i] != '\0')
charList.Add(array[j][i]);
}
}
return string.Join("", charList);
}
方法二 :按行排序
创建一个numRows行的字典,在字典中累加每行的字符,最后按行拼接,返回字符串
public static string Convert(string s, int numRows)
{
if (numRows == 1) { return s; }
Dictionary<int, List<char>> dic = new Dictionary<int, List<char>>();
int rowIndex = 0;
bool goingDown = false;
for (int i = 0; i < numRows; i++)
{
dic.Add(i, new List<char>());
}
foreach (char c in s)
{
dic[rowIndex].Add(c);
if (rowIndex == 0 || rowIndex == numRows - 1) { goingDown = !goingDown; }
rowIndex += goingDown ? 1 : -1;
}
string[] arr = new string[numRows];
foreach (var item in dic)
{
arr[item.Key] = string.Join("", item.Value);
}
return string.Join("", arr);
}
方法三: 按行访问
思路
按照与逐行读取 Z 字形图案相同的顺序访问字符串。
算法
首先访问 行 0 中的所有字符,接着访问 行 1,然后 行 2,依此类推…
对于所有整数 k,
行 0中的字符位于索引 k(2⋅numRows−2) 处;
行 numRows−1 中的字符位于索引 k(2⋅numRows−2)+numRows−1 处;
内部的 行 i 中的字符位于索引 k(2⋅numRows−2)+i 以及 (k+1)(2⋅numRows−2)−i 处;
public static string Convert(string s, int numRows)
{
if (numRows == 1) return s;
string ret="";
int cycleLen = 2 * numRows - 2;//每周期字符个数
for (int i = 0; i < numRows; i++)
{
for (int j = 0; j + i < s.Length; j += cycleLen)
{
ret += s[j + i];
if (i != 0 && i != numRows - 1 && j + cycleLen - i < s.Length)
ret += s[j + cycleLen - i];
}
}
return ret;
}