试水刷题,先从简单的练起。

题目

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)
}

实际中这两个版本跑起来都蛮快的,并没有太大区别

文章目录