leetcode刷题日记—— Z 字形变换
[ 题目描述 ]:
[ 思路 ]:
- 题目要求将一个字符串按照给定的行数进行 z 字形排列,然后读取每一行组成的新的字符串
- 最简单的想法就是遍历字符串,对每个字符从 0 - numRows - 0,这样的顺序去存储每个字符所在的行,然后遍历每一行放入答案数组
- 运行如下
char* convert(char* s, int numRows) {
int len=strlen(s);
if(len==1 || numRows==1) return s;
bool is_reverse=false;
int* char_index=(int*)malloc(sizeof(int)*(len));
char* ans=(char*)malloc(sizeof(char)*(len+1));
ans[len]='\0';
int index=0;
for(int i=0;i<len;i++){
if(is_reverse){
char_index[i]=index--;
}else{
char_index[i]=index++;
}
if(index==numRows-1 || index==0){
is_reverse=!is_reverse;
}
}
int row=0,ans_index=0;
while(row<numRows){
for(int i=0;i<len;i++){
if(char_index[i]==row){
ans[ans_index++]=s[i];
}
}
row++;
}
free(char_index);
return ans;
}
[ 优化 ]:
- 上面的解法使用了很多的额外空间,并且这题的重新排列的顺序是由规律的,那是否可以根据这一规律,对每行元素的位置进行确定
- 由题意可以发现,一个完整Z字形周期为 2 * numRows - 2,因为第一行和最后一行在一个完整的 z 字周期中,仅只有一个元素,其他行均为二
- 按行处理字符串, 对于每一行 i,从该行的起始位置开始
- 垂直向下的字符位于 j + i
- 斜向上的字符位于 j + cycleLen - i(首行和末行除外)
- 运行如下
char* convert(char* s, int numRows) {
if (numRows==1) return s;
int len=strlen(s);
char* ans=(char*)malloc(len + 1);
ans[len] = '\0';
int index=0;
int cycleLen=2 * numRows - 2;
for (int i = 0; i < numRows; i++) {
for (int j = 0; j + i < len; j += cycleLen) {
ans[index++] = s[j + i];
if (i != 0 && i != numRows - 1 && j + cycleLen - i < len) {
ans[index++] = s[j + cycleLen - i];
}
}
}
return ans;
}
[ 官方题解 ]:
- 一、利用二维矩阵模拟,就是创建一个矩阵,然后将字符按照 z 字形,存放在这个二维矩阵中,再遍历这个二维矩阵的每一行,得出答案。其实和第一种解法一样,只是我存储的是每个字符的所在的行数
- 二、压缩矩阵空间,在方法一的基础上,削减了没有用上的空间。主要通过为每一行去初始化一个空列表,然后遍历字符串,将每个字符插入对应行的列表的末尾
- 三、直接构造,通过 Z 字形变换的规律来做的,就是上面优化的算法