一、问题描述
The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
And then read line by line: “PAHNAPLSIIGYIR”
Write the code that will take a string and make this conversion given a number of rows:
string convert(string text, int nRows);
convert(“PAYPALISHIRING”, 3) should return “PAHNAPLSIIGYIR”.
二、思路
- 感觉是个数学问题,罗列几个例子,便于查看。
- 一开始自己理解错了,理解成如下的方式了。
- 正确的理解应该是如下:
计算了每个模式的个数Rows+(Rows-2)
计算了每一行的列数,即每一行的元素个数。不过看了其他人的,貌似不需要计算。。。
三、程序示例
C#版本
- 正确ZigZag
class Program
{
//正确的zigzag
public static string Convert(string s, int numRows)
{
if (s.Length < 2 || numRows==1)
{
return s;
}
char[] result = new char[s.Length];
//一组元素个数
int pattern = numRows + (numRows - 2);
//完整的组数
int num = s.Length / pattern;
//剩余字符个数,小于pattern
int remain = s.Length % pattern;
//计算zigzag结构每行元素个数
int[] numsOfRow = new int[numRows];
for (int i = 0; i < numRows; i++)
{
//考虑两种情况
//1.当剩余数量小于等于行数时
if (remain <= numRows)
{
if (i < remain)
{
if (i==0 || i==numRows-1)
{
numsOfRow[i] = num + 1;
}
else
{
numsOfRow[i] = 2 * num + 1;
}
}
else
{
if (i == 0 || i == numRows - 1)
{
numsOfRow[i] = num;
}
else
{
numsOfRow[i] = 2 * num;
}
}
}
//2.当剩余数量大于行数时
else
{
if (i == 0 || i == numRows-1)
{
numsOfRow[i] = num + 1;
}
else
{
if (i >= pattern - (remain-1))
{
numsOfRow[i] = 2 * (num + 1);
}
else
{
numsOfRow[i] = 2 * num + 1;
}
}
}
}
//最后逐行输出,得到结果
int pos = 0;
for (int row = 0; row < numRows; row++)
{
for (int col = 0; col < numsOfRow[row]; col++)
{
if (row == 0 || row == numRows-1)
{
result[pos++] = s[row + col * pattern];
}
else
{
//当前行偶数列
if (col % 2==0)
{
result[pos++] = s[row + (col / 2) * pattern];
}
//当前行奇数列
else if (col % 2 == 1)
{
result[pos++] = s[pattern - row + (col / 2) * pattern];
}
}
}
}
return new string(result);
}
static void Main(string[] args)
{
string str = "ABCDE";
int rows = 4;
string result = Convert(str, rows);
}
}
- 错误的个人理解方式对应的程序示例。
class Program
{
public static string Convert(string s, int numRows)
{
if (s.Length < 2 || numRows==1)
{
return s;
}
char[] result = new char[s.Length];
//一组元素个数
int pattern = numRows + (numRows - 2);
//完整的组数
int num = s.Length / pattern;
//剩余字符个数,小于pattern
int remain = s.Length % pattern;
//计算zigzag结构每行元素个数
int[] numsOfRow = new int[numRows];
for (int i = 0; i < numRows; i++)
{
//考虑两种情况
//1.当剩余数量小于等于行数时
if (remain <= numRows)
{
if (i < remain)
{
if (i==0 || i==numRows-1)
{
numsOfRow[i] = num + 1;
}
else
{
numsOfRow[i] = 2 * num + 1;
}
}
else
{
if (i == 0 || i == numRows - 1)
{
numsOfRow[i] = num;
}
else
{
numsOfRow[i] = 2 * num;
}
}
}
//2.当剩余数量大于行数时
else
{
if (i == 0 || i == numRows-1)
{
numsOfRow[i] = num + 1;
}
else
{
if (i <= remain - numRows)
{
numsOfRow[i] = 2 * (num + 1);
}
else
{
numsOfRow[i] = 2 * num + 1;
}
}
}
}
//最后逐行输出,得到结果
int pos = 0;
for (int row = 0; row < numRows; row++)
{
for (int col = 0; col < numsOfRow[row]; col++)
{
if (row == 0 || row == numRows-1)
{
result[pos++] = s[row + col * pattern];
}
else
{
result[pos++] = s[row + col * (pattern / 2)];
}
}
}
return new string(result);
}
static void Main(string[] args)
{
string str = "ABCDE";
int rows = 4;
string result = Convert(str, rows);
}
}
END,
2018.03.15更新简便方法
上面的方法太笨拙,不忍。于是参考博客,学习了更加简便的方法。
感谢博友分享。
http://blog.youkuaiyun.com/chilseasai/article/details/47209565
思路如下
- 计算循环结构,即V字形,大小: pattern = numRows + (numRows - 2);
- 每个V型的起始地址=c-r,其中c每次内循环自增pattern
对于首行、末行元素都是r + pattern*n
对于中间行,r行,V型组第一个元素对应的是s[r + pattern*n]
对于中间行,r行,V型组第二个元素对应的是s[(c-r)+(pattern-r)]=s[起始元素+循环结构内相对于起始元素偏移量] - 判断元素是否超出s的最长长度范围。
程序示例:
C#版本,简洁了许多。
class Program
{
//Z字型
public static string Convert(string s, int numRows)
{
if (s.Length < 2 || numRows == 1)
{
return s;
}
char[] result = new char[s.Length];
//一组V型元素个数
int pattern = numRows + (numRows - 2);
//每个V型的起始地址=c-r
//对于首行、末行元素都是r + pattern*n
//对于中间行,r行,V型组第一个元素对应的是s[r + pattern*n]
//对于中间行,r行,V型组第二个元素对应的是s[(c-r)+(pattern-r)]=s[起始元素+偏移量]
int pos = 0;
for (int r = 0; r < numRows; r++)
{
for (int c = r; c < s.Length; c+=pattern)
{
result[pos++] = s[c];
if (r!=0 && r!=numRows-1 && ((c-r)+(pattern-r)<s.Length))
{
result[pos++] = s[(c - r) + (pattern - r)];
}
}
}
return new string(result);
}
static void Main(string[] args)
{
string str = "ABCDE";
int rows = 4;
string result = Convert(str, rows);
}
}