0006 Z字形变换
题目链接: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
解法
/** 字符串可以看做字符数组,排列如下
*
* 0 2(n-1) 4(n-1)
* 1 2(n-1)-1 2(n-1)+1 4(n-1)-1 4(n-1)+1
* 2 . . . .
* . . . .
* . . .
* n-1 3(n-1)
*/
char* convert(char* s, int numRows) {
if( numRows == 1) return s;
int len = strlen(s);
if(len <= numRows) return s;
char * tmp = (char *)malloc(sizeof(char) * ( len + 10));
char * ans = tmp;
int i, j;
// 找到规律中的n-1
int val = numRows - 1;
int num;
// 计算第一行的个数num
if ((len-1) % (2 * val) == 0)
num = len / numRows + 1;
else
num = len / numRows;
// 将第1行有规律的数字加入结果中
for (i = 0; i < num; i++)
{
if(i * (2 * val) < len)
{
*tmp++ = s[i * (2 * val)];
}
}
// 计算第2行到倒数第2行,即索引j从 1到n-2
for (j = 1; j < numRows - 1; j++)
{
// 从上面规律中得知每行不超过2*num个,
// 且每行都跟2(n - 1)的倍数相关
for( i = 0; i < num; i++)
{
// 可以看出规律
int x = i * (2 * val) + j;
int y = (i + 1) * (2 * val) - j;
// 判断是否大于总长度
if( x < len)
{
*tmp++ = s[x];
}
if( y < len)
{
*tmp++ = s[y];
}
}
}
// 将最后一行有规律的数字加入结果
for (i = 0; i < num; i++)
{
int m = i * (2 * val) + val;
if (m < len)
{
*tmp++ = s[m];
}
}
*tmp = '\0';
return ans;
}