持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,[点击查看活动详情](juejin.cn/post/714765…
题目描述
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = "PAYPALISHIRING", numRows = 3
输出: "PAHNAPLSIIGYIR"
示例 2:
输入: s = "PAYPALISHIRING", numRows = 4
输出: "PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
示例 3:
输入: s = "A", numRows = 1
输出: "A"
提示:
1 <= s.length <= 1000s由英文字母(小写和大写)、','和'.'组成1 <= numRows <= 1000
解题思路
- 在一个z字形位置游走,最直接的是开一个二维数组,根据规则在对应位置填数,然后再正常的从左向右从上向下进行输出。因为开了二维数组,维度约为nrows*len(s)/2,化简在一些情况下为
O(n^2)的空间和时间复杂度,捉襟见肘。
func convert(s string, numRows int) string {
if len(s) == 1 || numRows == 1 {
return s
}
strs := []byte(s)
w := len(s)/2 + 1
m := make([][]byte, numRows)
for i := 0; i < len(m); i++ {
m[i] = make([]byte, w)
}
i := 0
x, y := 0, 0
for i < len(s) {
for x < numRows-1 && i < len(s) {
m[x][y] = strs[i]
i++
x++
}
for x > 0 && y < w && i < len(strs) {
m[x][y] = strs[i]
x--
y++
i++
}
}
ans := make([]byte, 0, len(s))
for _, bytes := range m {
for _, b := range bytes {
if b != 0 {
ans = append(ans, b)
}
}
}
return string(ans)
}
- 下面我们尝试找到字母顺序的数学规律,直接按规律输出即可。列表:
- 可以看到每一竖列,初值为行号,公差为2n-2;斜着的初值2n-2-行号,公差也是2n-2。这样子可以直接输出结果了。这样空间,时间复杂度都降为
O(n),不错不错。
func convert2(s string, numRows int) string {
if len(s) == 1 || numRows == 1 {
return s
}
strs := []byte(s)
m := make([]byte, 0, len(strs))
for i := 0; i < numRows; i++ {
for k := 0; i+k*(2*numRows-2) < len(strs); k++ {
m = append(m, strs[i+k*(2*numRows-2)])
if i == 0 || i == numRows-1 {
continue
}
if 2*numRows-2-i+k*(2*numRows-2) < len(strs) {
m = append(m, strs[2*numRows-2-i+k*(2*numRows-2)])
}
}
}
return string(m)
}