Loading...

# 6. 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

# 想法:

# 1. 数学模拟解法

对于一个 Z 字形变换,可以很明显的观察出,第一行和最后一行每个元素之间的间隔是 2*numRows-2 ,而每一行第一个元素我们又是已知的。那么很容易就会想到遍历行进行模拟。

0  6    12
1 57  1113
24 810 
3  9

那么如何确定当前行结束呢,这里采用的是轮数来决定。对于上述例子,第一轮指的是

0   
1  5
24
3

因此可以计算出最大轮数是 Math.ceil(s.length/(2*(numRows)-2));

接下来就是中间行的处理,对于每一轮来说,一行会有两个元素,且每个元素之间的索引差是 2*(numRows-row)-2 , 其中 row 表示的就是当前行。那么只需要计算出每一轮第一个元素的索引即可。
这个也很好计算,因为每行第一个元素就是 row ,而每轮之间的索引差也是固定的,所以可以算出,中间行每轮的第一个元素索引是 row+(2*(numRows)-2)*(count);
因此,整个代码就很简单了。

# 代码
s
var convert = function(s, numRows) {
    if(numRows===1||numRows>=s.length){
        return s;
    }
    let res=[];
    const fill=(row,s)=>{
        let count=0;
        let max=Math.ceil(s.length/(2*(numRows)-2));
        let i=row;
        while(count++<max){
            if(s[i]) res.push(s[i]);
            // 中间行需要特别注意
            if(row!=0&&row!=numRows-1){
                i=i+2*(numRows-row)-2;
                if(s[i])
                res.push(s[i]);
            }
            i=row+(2*(numRows)-2)*(count);
        }
    }
    for(let i=0;i<numRows;i++){
        fill(i,s);
    }
    return res.join('');
};

# 2. 直接模拟法

上述的模拟还是比较麻烦的,更近一步的,我们会注意到,在 Z 字形变换的时候,填入时行序列是从 0numRows , 再从 numRows0 ,我们只要模拟这个行索引的变换过程就可以快速解答出来。

s
var convert = function(s, numRows) {
    if(numRows===1||numRows>s.length){
        return s;
    }
    let res=new Array(numRows).fill("");
    let i=0;
    let flag = -1;
    for (let c of s){
        res[i] += c
        if(i == 0 || i == numRows -1) flag = - flag;
            i += flag;
    }
    return "".concat(...res)
};
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

jluyeyu 微信支付

微信支付

jluyeyu 支付宝

支付宝