将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zigzag-conversion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:找规律,根据样例有可以得到如下规律
LEETCODEISHIRING 3
拆分为:
LCIR
ETOESIIG
EDHN
可以看出分为3行,每行开头字母就是原字符串对应的前3个
第一行字母在原字符串下标:0,4,8,12
第二行字母在原字符串下标:1,3,5,7,9,11,13,15
底三行字母在原字符串下标:2,6,10,16
可以发现规律,第一行和最后一行很特殊,都是从对应字母的下标开始一直+4,中间第2行一直+2
而4=(3-1)*2,2=(3-2)*2
那么我们是不是可以认为第一行和最后一行都是直接对应的字母下标一直+(n-1)*2,中间的都是直接对应字母下标+(n-2)*2
再来看另外一个样例进行验证:
LEETCODEISHIRING 4
LDR
EOEII
ECIHN
TSG
对应下标:
第1行:0,6,12
第2行:1,5,7,11,13
第3行:2,4,8,10,14
第4行:3,9,15
规律如下:
第一行和最后一行满足对应开始下标+(n-1)*2,但中间不符合对应开始下标+(n-2)*2。
可以发现第2行下标轮次+(n-2)*2,再+2,
然后第3行下标轮次为+(n-2)*2-2,+4,
那么是否可以假定,第一行和最后一行满足对应开始下标+(n-1)*2,而从第2行开始,分别轮次+(n-2)*2,+2
第3行开始,分别轮次+(n-2)*2-2,+4,
第4行开始,分别轮次+(n-2)*2-4,+6
…
一直这样下去呢,我们再手动模拟一组比较复杂的数据:
ABCDEFGHIJKLMNOPQNG 5
得到:
AIQ
BHJPN
CGKOG
DFLN
EM
下标分别为:
第1行:0,8,16
第2行:1,7,9,15,17
第3行:2,6,10,14,18
第4行:3,5,11,13
第5行:4,12
发现我们的假设成立。
class Solution {
public:
string convert(string s, int numRows) {
int n=numRows;
if(n==1)
return s;
string t;
//定义中间最开始的一行需要轮次加的数值
int l=(n-2)*2;
int r=2;
for(int i=0;i<s.length();i++)
{
//最开始的和最后的一行单独计算
if(i==0||i==n-1)
{
t+=s[i];
for(int j=1;;j++)
{
int k=(n-1)*2*j+i;
if(k>=s.length())break;
t+=s[k];
}
}
//中间的轮流计算
else
{
t+=s[i];
int k=i;
int ans=0;
while(true)
{
//轮次计算
if(ans%2==0)
k+=l;
else k+=r;
ans++;
//int k=(n-2)*2*j+i;
if(k>=s.length())break;
t+=s[k];
}
l-=2;
r+=2;
}
if(t.length()==s.length())
break;
}
return t;
}
};