目录(快速导航)
题目描述
视频讲解 https://www.bilibili.com/video/av65798417/
思路
代码
题目描述:
题目链接:https://leetcode-cn.com/problems/zigzag-conversion/
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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);
视频讲解
https://www.bilibili.com/video/av65798417/
思路:
看到这道题,首先想到的就是找规律,只要从每一个行的角度出发,找到每一行中连接字符在字符串中出现的位置的规律,那么就可以解决这个问题。
首先使用数字标示字符串的下标如下,按照从上到下,从左到右标示:
0 6 12
1 5 7 11 13
2 4 8 10 14
3 9 15
可以发现如下规律:
- z字形的行数已知,并且第i行的开头字符为s[i];(ps:i从0开始,即第0行为S[0]) =》 所以我们从每一行出发,把每一行的字符拼成该行的字符串,之后再把所有行的字符串连接起来,不就ok了,现在找每一行内字符下标的规律。
- 第0行与最后一行的规律一致;以第一行为例子,我们称0到6,6到12为一个gap,并且0为gap头,6为gap尾,那么第0行了最后一行的gap大小都为6,所以这两行,就特别简单,若行数为numRows,那么gap大小为:2*(numRows-1),为什么是这个呢?观察从0到6的过程中,1和4在第1行,2和5在第二行,3独自在最后一行,但是加上6本身的位置,就看成3和6一个组,所以说从第0行开始往下,都是以2个字符为一组的形式出现了行高numRows-1次,那就是这个规律了;
- 中间行的规律一致;中间行对比第0行与最后一行,在gap大小上都一致,如1到7,gap为6。只是说他们在gap间多了一个字符,计为middle,如4。并且这个字符下标的规律和所在行高有关,如果在第i 行,其middle的下标为:gap头+2*(numRows-i-1)。这个类似的,只是将视角放过来,从上往下看,如第1行的1和5的gap之间有一个middle为5,那么此时1为gap头,向下2和4为一组,3和5为一组,共2组,4个元素,符合2*(numRows-i-1) = 2*(4-1-1)=4,那么niddle为1+4=5。
好了,每一个gap的规律都一致,所以我们只需要一个for循环,遍历每一行,对于第0行和最后一行,使用规律2,不停的迭代gap,直到超过S的size;对于中间行,同样使用规律2迭代gap,只是在每一个gap中,使用规律3计算middle即可。
代码:
class Solution {
public:
string convert(string s, int numRows) {
// 特殊情况
if(numRows == 1)
return s;
int gap = 2*(numRows-1);
string out = "";
int i=0;
// 迭代每一行 获得每一行的拼接字符串tmp
for (i = 0; i < numRows; ++i) {
int j=i;
string tmp = "";
// 迭代直到下标超限
while(j<s.size()){
// 在tmp上加上这次gap的gap头
tmp += s[j];
// 检查是否有midlle 如果有就在tmp上加上
int middle = j+ 2*(numRows-i-1);
if(i!=0 && i!=(numRows-1) && middle<s.size()){
tmp += s[middle];
}
// 将本次gap的gap尾 当作下次gap的gap头
j+=gap;
}
// 拼接所有行的tmp
out += tmp;
}
return out;
}
};