题目描述
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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字形排列的二维数组,但是没必要。
把整个字符串分成多个block,类似于一个V,如示例2中,则把LEETCO作为一个block,不足一个block的按照一个来看,那么就有len(s)/block_size个block,block_size与numRows有关,即block_size=2*numRows-2。可以看出,按照这样划分后,每个block的第一行和最后一行只有一个元素,其余行都有最多两个元素。每个block的元素下标是确定的,第i个(i=0,1,…)block的第一个字符的下标为i*block_size。
将字符串分块并确定下标后,就可以一层层的来输出字符串了。
需要特殊处理的是空串以及numRows=1的情况,直接返回原字符串即可。
代码实现
C++
/*
* @lc app=leetcode.cn id=6 lang=cpp
*
* [6] Z 字形变换
*/
// @lc code=start
class Solution {
public:
string convert(string s, int numRows) {
if(s.size() == 0 || numRows == 1){
return s;
}
string ans = "";
string tmp = "";
int block_size = 2 * numRows - 2;
int block = (s.size() + block_size - 1) / block_size;
for(int i = 0; i < block; i++){
ans += s[i*block_size];
int index = i*block_size + numRows - 1;
if(index < s.size()){
tmp += s[index];
}
}
for(int i = 1; i < numRows - 1; i++){
for(int j = 0; j < block; j++){
int index1 = j*block_size + i;
int index2 = (j+1)*block_size - i;
if(index1 < s.size()){
ans += s[index1];
}
if(index2 < s.size()){
ans += s[index2];
}
}
}
ans += tmp;
return ans;
}
};
// @lc code=end
Java
/*
* @lc app=leetcode.cn id=6 lang=java
*
* [6] Z 字形变换
*/
// @lc code=start
class Solution {
public String convert(String s, int numRows) {
if(s.length() == 0 || numRows == 1){
return s;
}
String ans = "";
String tmp = "";
int block_size = 2 * numRows - 2;
int block = (s.length() + block_size - 1) / block_size;
for(int i = 0; i < block; i++){
ans += s.charAt(i*block_size);
int index = i*block_size + numRows - 1;
if(index < s.length()){
tmp += s.charAt(index);
}
}
for(int i = 1; i < numRows - 1; i++){
for(int j = 0; j < block; j++){
int index1 = j*block_size + i;
int index2 = (j+1)*block_size - i;
if(index1 < s.length()){
ans += s.charAt(index1);
}
if(index2 < s.length()){
ans += s.charAt(index2);
}
}
}
ans += tmp;
return ans;
}
}
// @lc code=end
Python
#
# @lc app=leetcode.cn id=6 lang=python3
#
# [6] Z 字形变换
#
# @lc code=start
class Solution:
def convert(self, s: str, numRows: int) -> str:
if(len(s) == 0 or numRows == 1):
return s
ans = ""
tmp = ""
block_size = 2 * numRows - 2
block = (len(s) + block_size - 1) // block_size
for i in range(block):
ans += s[i*block_size]
index = i*block_size + numRows - 1
if(index < len(s)):
tmp += s[index]
for i in range(1,numRows-1):
for j in range(block):
index1 = j*block_size + i
index2 = (j+1)*block_size - i
if(index1 < len(s)):
ans += s[index1]
if(index2 < len(s)):
ans += s[index2]
ans += tmp
return ans
# @lc code=end