leetcode-cn 题解 6. Z 字形变换
试水刷题,先从简单的练起。
题目
6. Z 字形变换
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
解题思路
这道题其实相对还是比较简单的,有很多种解法,这里先只说其中一种
首先还是老样子,构造测试数据,画图,这次我们假设字符串的内容就和下标一样,方便观察。
这是按照题目给出的样式进行排列的,可以看到的是,在中间的斜线部分,每一列每一行其实只有一个字符,那我们就可以把它压缩一下。
压缩之余,我顺便给它上了个颜色,可以看到,这些字符其实是 6 个一组,不断重复排列下去的。
那么接下来,我们设行数为 n
,每组的长度为 q
,很显然 q = 2n-2
。
我们把 n 和 q 带进去继续画图,因为算式比较长,每个格子只好变胖一点点了。
其实到这一步的时候已经比较明朗了,每一横行字符的下标其实可以直接算出来,只需要不断的计算后面那一组就可以了,至于第一行和最后一行,特殊处理下就好。
解答
func convert(s string, numRows int) string {
if numRows == 1 || len(s) <= numRows{
return s
}
groupLen := numRows*2 - 2
groupNum := int(math.Ceil(float64(len(s)) / float64(groupLen)))
var ansString []byte
for i := 0; i < numRows; i++{
//计算第 i 行字符串
for j := 0; j < groupNum; j++ {
//计算第 j 组字符串
charIndex := groupLen*j + i
if charIndex >= len(s) {
continue
}
ansString = append(ansString, s[charIndex])
if i != 0 && i != numRows-1 {
charIndex = groupLen*(j+1) - i
if charIndex < len(s) {
ansString = append(ansString, s[charIndex])
}
}
}
}
return string(ansString)
}
这里其实还可以做点小优化,其实并不需要计算出组数,下标爆了就 continue 就好了,可以直接 while 循环搞起。
func convert(s string, numRows int) string {
if numRows == 1 || len(s) <= numRows{
return s
}
groupLen := numRows*2 - 2
var ansString []byte
for i := 0; i < numRows; i++{
//计算第 i 行字符串
left := i
right := groupLen - left
for {
if left >= len(s) {
break
}
ansString = append(ansString, s[left])
left += groupLen
if i != 0 && i != numRows-1 {
if right >= len(s) {
break
}
ansString = append(ansString, s[right])
right += groupLen
}
}
}
return string(ansString)
}
实际中这两个版本跑起来都蛮快的,并没有太大区别
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。