来源:力扣(LeetCode)
链接: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);
示例 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
题解
这个Z字型其实是这样的:
每一行字母的所有下标其实是有规则的
我们先假定有numRows=4行来推导下,其中2numRows-2 = 6, 我们可以假定为step=2numRows-2,我们先来推导下规则:
第0行下标:0 、6 、12 、18
下标间距 :6 - 6 - 6 ==> 下标间距step - step - step
第1行下标:1、5、 7 、11、13
下标间距:4、2、4 、2==> 下标间距step-2x1(行)、2x1(行)、step-2x1(行)、2x1(行)
第2行下标:2、4、8 、10、14
下标间距:2、4、2、4 ==> 下标间距step-2x2(行)、2x2(行)、step-2x2(行)、2x2(行)
第3行下标:3、9 、15、21
下标间距间距:6、6、6 ==>下标间距step、step、step
可以得出以下结论:
1、 起始下标都是行号
2、 第0层和第numRows-1层的下标间距总是step 。
3、中间层的下标间距总是step-2x(行数i),2x(行数i)交替。
4、下标不能超过len(s)-1
代码
记得提交的时候把汉字注释去掉,不然会报内部出错
char* convert(char* s, int numRows){
if (numRows == 1){ // 1就不用变换
return s;
}
int key=0; // 改变指针
int step = numRows * 2 - 2; // 间距
int index = 0; // 记录s的下标
int add = 0; // 真实的间距
int len=strlen(s); // 字符串长度
char* z=(char*)malloc(sizeof(char)*(len+1)); // 分配空间,至少 len+1,不然会出现越界错误
for(int i=0;i<numRows;i++){
index = i; // 每行开始初始下标
add = i*2;
while (index < len){ // 超出字符串长度计算下一层
*(z+key)= s[index]; // 当前行的第一个字母
key++;
add = step - add; // 第一次间距是 step-2*i,第二次是 2*i
index += (i == 0 || i == numRows-1) ? step : add; // 0行和最后一行使用step间距,其余使用add间距
}
}
z[len] = '\0'; // 截止符,不然会出现越界错误
return z;
}
调试
#include<stdio.h>
#include<string.h>
#include<malloc.h>
int main(){
char* s=(char*)"LEETCODEISHIRING";
char* z1=convert(s,3);
printf("numRows=%d ",3);
printf("%s",z1);
printf("\n");
char* z2=convert(s,4);
printf("numRows=%d ",4);
printf("%s",z2);
return 0;
}