原题链接:ZigZag Conversion
一开始的思路是根据所给字符串及 Z 型串的行数计算出末元素所在的行列数,进而用二维数组来计算blabla…但算到后期发现不用这么复杂。。。而是直接去找Z 型串每行元素的下标关系。
原理如下图

对于给定的 z 型串,我们取 2*numRows-2为一个周期(除数)(图中红色箭头轨迹为一个周期),以字符串 s 的长度为被除数;z 型串的第一行元素所在位置除以除数,余数皆为 1,第二行元素所在位置除以除数余数,余数为 0 或 2,第 3~numRows-1 行,余数皆为 n 或 2*numRows-n,以此类推,最后一行余数为 numRows,每处理一行就将字符追加到串尾,最后既得结果。
代码如下:
string convert(string s, int numRows)
{
auto len = s.length();
string s1;
if (1 == numRows || s.length() < 3) // 特殊情况处理
return s;
else
{
if (2 == numRows) // 行数等于2时,直接交叉赋值
{
for (int i = 0; i < len; i = i+2)
s1.push_back(s.at(i));
for (int i = 1; i < len; i = i+2)
s1.push_back(s.at(i));
return s1;
}
else // 行数大于2时
{
for (int j = 0; j < len; j++) // 余数为 1 时
if ((j+1) % (2*numRows-2) == 1)
s1.push_back(s.at(j));
for (int j = 0; j < len; j++) // 余数为 0 或 2 时
if ((j+1) % (2*numRows-2)==0 || (j+1) % (2*numRows-2)==2)
s1.push_back(s.at(j));
for (int i = 3; i < numRows; i++) // 余数为 n 或 2r-n 时
for (int j = 0; j < len; j++)
if ((j+1) % (2*numRows-2)==i || (j+1) % (2*numRows-2)==2*numRows-i)
s1.push_back(s.at(j));
for (int j = 0; j < len; j++) // 余数为 r 时
if ((j+1) % (2*numRows-2)==numRows)
s1.push_back(s.at(j));
return s1;
}
}
}
复杂度

enmmmmm,,就是 Runtime 有点感人(:
考虑再进一步优化,上面的代码中,对 z 型串每一行元素位置遍历(即各个余数)时都是从串首到串尾逐个遍历的,但其实仔细观察上面的图会发现 z 型串每一行的元素前后位置(下标)是有关系的,这样我们就不用 j++了,而是更加智能的调整步长:
string convert(string s, int numRows)
{
auto len = s.length();
string s1;
if (1 == numRows || len < 3 || numRows >= len) // 特殊情况处理
return s;
else
{
if (2 == numRows) // 行数等于2时,直接交叉赋值
{
for (int i = 0; i < len; i = i+2)
s1.push_back(s.at(i));
for (int i = 1; i < len; i = i+2)
s1.push_back(s.at(i));
return s1;
}
else // 行数大于2时
{
for (int j = 0; j < len; j = j+2*numRows-2) // 余数为 1 时
s1.push_back(s.at(j));
for (int j = 1; j < len; ) // 余数为 0 或 2 时
{
if ((j+1) % (2*numRows-2)==0)
{
s1.push_back(s.at(j));
j = j + 2;
continue;
}
if((j+1)%(2*numRows-2) == 2)
{
s1.push_back(s.at(j));
j = j+2*numRows-4;
}
}
for (int i = 3; i < numRows; i++) // 余数为 n 或 2r-n 时
for (int j = i-1; j < len; )
{
if ((j+1) % (2*numRows-2)==i)
{
s1.push_back(s.at(j));
j = j+2*(numRows-i+1)-2;
continue;
}
if ((j+1)%(2*numRows-2) == 2*numRows-i)
{
s1.push_back(s.at(j));
j = j+i*2-2;
}
}
for (int j = numRows-1; j < len; j = j+2*numRows-2) // 余数为 r 时
s1.push_back(s.at(j));
return s1;
}
}
}
复杂度

奥利给 !

本文介绍了一种ZigZag字符串转换算法,通过分析字符串及其Z型排列的行数,采用周期性的数学关系,优化了遍历过程,提高了算法效率。特别地,文章详细解释了如何利用元素下标关系进行快速定位,避免了不必要的遍历。
455

被折叠的 条评论
为什么被折叠?



