leetcode 6. Z 字形变换(Java版)

2019-02-20  本文已影响0人  M_lear

题目描述(题目难度,中等)

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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

示例代码

时间复杂度为O(n),空间复杂度为O(n)

class Solution {
    public String convert(String s, int numRows) {
        if(s == null || s.length() == 0 || numRows <= 1){
            return s;
        }
        StringBuilder sb = new StringBuilder(s.length());
        int a, j;
        for(int i = 0; i < numRows; ++i){
            a = 0;
            j = i;
            while(true){
                if(j < s.length()){
                    sb.append(s.charAt(j));
                }else break;
                if((a ^= 1) == 1){
                    j += 2*((numRows - i - 1)==0 ? i : numRows - i - 1);
                }else{
                    j += 2*(i == 0 ? numRows - i - 1 : i);
                }
            }
        }
        return sb.toString();
    }
}

思路解析

这个题目本质上不难,其实就是找规律加上一点编码技巧。既然这是一道找规律的题,那么废话不多说,直接上例子来找规律。
当排列行数为 n=3 时:(没加括号的数字表示在原字符串中的下标,加括号的数字为相邻两数字的差)

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

当排列行数为 n=4 时:

0 (6) 6 (6)       12
1 (4) 5 (2) 7 (4) 11 (2) 13
2 (2) 4 (4) 8 (2) 10 (4) 14
3 (6)       9 (6)        15

当排列行数为 n=5 时:

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

规律如下:
按行看,
第 0 行和第 n-1 行的下标间距为 2*(n-1),
当 i = 1 到 n-2 时,第 i 行的下标间距为 2*(n - 1 - i) 和 2*i 交替。
编码技巧如下:
从上面可以知道,中间行的下标间距是在两个值之间来回变动的。我们可以使用一点小技巧方便的判断当前的间距应该是哪个值,使得代码更简洁优美。
下面两点小技巧效果是等同的:

  1. 利用异或运算,假设初始化 a = 0,每次操作完后,令 a = a ^ 1,就可以自动让 a 在 0,1 之间来回变动,我们只需要判断当前的 a 为何值就可知道现在应该是用哪个间距值。
  2. 我们也可以初始化 a = -1,然后每次操作完后,令 a = -a,可以让 a 在 -1,1 之间来回变动,从而实现相同的效果。

此外,就具体语言来说,本题使用的是 Java 语言,还有一个与 Java 有关的知识点,即 String,StringBuilder 和 StringBuffer 的区别。其中 String 是常字符串,StringBuilder 和 StringBuffer 是可变字符串。而 StringBuilder 和 StringBuffer 的区别是前者线程不安全,适合单线程的情况, 后者线程安全,适合多线程的情况。综上,本题应当使用 StringBuilder 临时保存结果。

上一篇下一篇

猜你喜欢

热点阅读