LeetCode No6 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

思路

模拟

题目的操作并不复杂,可以直接按照题目意思直接模拟,将字符串转化成一个矩阵,然后再遍历矩阵即可得到最后的字符串。但是这种方式提交很容易超时,而且构建出的矩阵有很大部分都是浪费掉了。

直接构造

相对于模拟得到最后的矩阵,其实我们并不在意最后的矩阵到底是什么样子的,我们如果能够明白构建矩阵的规律,那么就可以直接按照规律去取数,不需要真正的构建矩阵,那么我们先研究下当行数numRows 小于4的时候分别是什么样子。
numRows 为1:

0 1 2 3 4 5 6 7 ... n

numRows 为2:

0 2 4 6 ... n-1
1 3 5 7 ... n

numRows 为3

0   4   8     12  
1 3 5 7 9  11 
2   6   10 

numRows 为4

0    6      12      18
1  5 7   11 13    17
2 4  8 10   14  16
3    9      15

可以看到其实所有的变幻操作都是在循环的打钩 [ √ ],以numRows=4为例:

0    | 6      | 12       |18   
1  5 | 7   11 | 13    17 |19     23
2 4  | 8 10   | 14  16   |20  22
3    | 9      | 15       |21

而每次打钩 [ √ ]所需要的字符个数t也是和numRows有关:

当numRows=1时:t=1
当numRows=2时:t=2
当numRows=3时:t=4
当numRows=4时:t=6
...
当numRows=n时:t=2*n-2

那这样我们就可以推断出numRows=n的时候,所循环的钩 [ √ ]应该如下[t=2*n-2]:

0
1               t-1
2             t-2
3           t-3
4         t-4
5       t-5
6     t-6
......
n-1

那这个时候我们只需要用for循环按行去读取对应的字符,也就不需要在代码中构建出最后的矩阵了。

AC代码

模拟

点击查看代码
class Solution {
    public String convert(String s, int numRows) {
        if( numRows == 1 ) {
            return s;
        }
        char[] chars = s.toCharArray();
        int len = chars.length;
        char[][] charss = new char[numRows][len];
        int i = 0;
        int j = 0;
        int index = 0;
        while( index<len ) {
            if( i==0 ) {
                if( j!=0 ) {
                    // 第一次的时候是以第一行为起点,其他循环次数的时候是一第二行为起点
                    i ++;
                }
                while( i < numRows && index<len ) {
                    charss[i][j] = chars[index];
                    i ++;
                    index ++;
                }
                i --;
            }
            if( i == numRows-1 ) {
                while(i>0 && index<len ) {
                    i --;
                    j ++;
                    charss[i][j] = chars[index];
                    index ++;
                }
            }
        }
        StringBuffer sb = new StringBuffer();
        for(i=0; i<numRows; i++) {
            System.out.println();
            for(j=0; j<len; j++) {
                System.out.print(charss[i][j] + " ");
                if(Character.isLetter(charss[i][j]) || charss[i][j]=='.' || charss[i][j]==',') {
                    sb.append(charss[i][j]);
                }
            }
        }
        return sb.toString();
    }
}

直接构造

点击查看代码
class Solution {
    public String convert(String s, int numRows) {
        int len = s.length();
        if (numRows == 1 || numRows >= len) {
            return s;
        }
        char[] chars = s.toCharArray();
        StringBuffer sb = new StringBuffer();
        int t = numRows * 2 - 2;
        for (int i = 0; i < numRows; ++i) {
            // 循环打√
            for (int j = 0; j + i < len; j += t) {
                sb.append(chars[j+i]);
                // 找一次循环的第二个值,同时第一行和最后一行只有一个值,不需要找
                if (0 < i && i < numRows - 1 && j + t - i < len) {
                    sb.append(chars[j + t - i]);
                }
            }
        }
        return sb.toString();
    }
}
posted @ 2022-04-11 21:27  Asimple  阅读(20)  评论(0编辑  收藏  举报