力扣第6题-Swift题解:Z字型变换

模拟题

题目描述

将一个给定字符串 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 <= 1000
  • s 由英文字母(小写和大写)、',''.' 组成
  • 1 <= numRows <= 1000

来源:
力扣(LeetCode)

思路

这道模拟题的关键思路是坐标变换,即需要对两个字符串的坐标进行映射。

假定输入字符串为s,输出字符串为p,那么映射的思路分两种,一种是从第一个下标开始遍历s,寻找在p对应的下标;第二种思路是反过来从第一个下标遍历p,寻找在字符串s中对应的下标。第二种思路会更好计算一点。

观察字符串s的“前进”规律可以发现,字符串中的字符要么是向下运动,要么是斜线向上运动。
而对于字符串p,它是负责逐字符行打印Z型中的每一行的。

计算规律如下:

  1. 对于z型的任意第i行的起始字符,都对应字符串s的第i个字符。
  2. 对于z型的任意字符来说,只要该在z字型中往右移动一次,要么是通过先向下移动再斜向上移动的方式,要么是通过先斜向上移动再向下移动的方式进行。
  3. 对于首行z型字符而言,始终往右移一位是通过向下移动再斜向上移动方式进行。
  4. 对于末行z型字符而言,始终往右移一位是通过向下移动再斜向上移动方式进行。
  5. 对于既非首行也非末行的其它z型字符而言,从首列开始,往右移动的移动规律是先向下移动再斜向上移动,下一步骤是先斜向上再向下移动交替进行。

利用如上描述的规律,就可以写代码模拟z型运动逻辑。通过逐行扫描z型字符,即可把对应的字符写入到p中。

swift代码:

class Solution {
    func convert(_ s: String, _ numRows: Int) -> String {
        guard numRows > 1 else { return s }
        let cs = s.cString(using: .ascii)!
        let count = cs.count
        var ans: [CChar] = Array(repeating: 0, count: count)

        var i1 = 0
        var i0 = 0
        var row = 0
        // 标记下一步移动是先向下,还是先斜向上
        var down = true 
        while i1 < count - 1 {
            ans[i1] = cs[i0]
            i1 += 1
            // 对于不同的移动方式,计算对应的偏移索引
            i0 += down ? (numRows-row-1)*2 : row*2
            if i0 >= count - 1 {
                row += 1
                i0 = row
                down = row == numRows - 1 ? false : true
            } else if row != 0 && row != numRows - 1 {
                down.toggle()
            }
        }

        return String(cString: ans)
    }
}

你可能感兴趣的:(力扣第6题-Swift题解:Z字型变换)