1. 程式人生 > 其它 >Leetcode 6. Z 字形變換

Leetcode 6. Z 字形變換

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"

方法一:找規律

​ 以 s = "PAYPALISHIRING", numRows = 3 為例,仔細分析

	 P   A   H    N
下標 0   4   8    12
	 A P L S I I  G
下標 1 3 5 7  9 11 13
	 Y   I   R
下標 2   6   10

可以得到以下規律:

  1. 第一行元素的下標對 4 求餘數全得 0
  2. 最後一行元素的下標對 4 求餘數全得 2
  3. 第二行元素的下標對 4 求餘數全得 1 或者 3,而 1+3=4

4=2*(3-1)=2*(numRows-1)

numRows = 4的時候

    P     I    N
    0     6    12
    A   L S  I G
    1   5 7  11 13
    Y A   H R
    2 4   8 10
    P     I
    3     9
  1. 第一行元素的下標對 6 求餘數全得 0
  2. 第二行元素的下標對 6 求餘數全得 1 或者 5
    ,而 1+5=6
  3. 第三行元素的下標對 6 求餘數全得 2 或者 4,而 2+4=6
  4. 第四行元素的下標對 6 求餘數全得 3
class Solution {
    public String convert(String s, int numRows) {
        if (numRows < 2)
            return s;
        int length = s.length();
        int num = 2 * (numRows - 1);
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < numRows; i++) {
            for (int j = 0; j < length; j++) {
                if (j % num == i || j % num == num - i) {
                    builder.append(s.charAt(j));
                }
            }
        }
        return builder.toString();
    }
}

方法二:模擬

以下思路來自於 Leetcode 大神,閃瞎我的眼。

連結:https://leetcode-cn.com/problems/zigzag-conversion/solution/zzi-xing-bian-huan-by-jyd/。

  • 字串 s 是以 Z 字形為順序儲存的字串,目標是按行列印。
  • numRows 行字串分別為 \(s_1,s_2,..., s_n\),則容易發現:按順序遍歷字串 \(s\) 時,每個字元 \(c\)\(Z\) 字形中對應的 行索引 先從 \(s_1\)增大到 \(s_n\),再從 \(s_n\)減小至 \(s_1\)…… 如此反覆。
  • 因此,解決方案為:模擬這個行索引的變化,在遍歷 s 中把每個字元填到正確的行 res[i]

演算法流程:

  1. res[i] += c 把每個字元 c 填入對應行 \(s_i\)
  2. i += flag 更新當前字元 c 對應的行索引;
  3. flag = - flag 在達到 \(Z\) 字形轉折點時,執行反向。

複雜度:

  • 時間複雜度 $O(N) $ :遍歷一遍字串 s
  • 空間複雜度 \(O(N)\) :各行字串共佔用 \(O(N)\)額外空間。
class Solution {
    public String convert(String s, int numRows) {
        if (numRows < 2) {
            return s;
        }
        List<StringBuilder> rows = new ArrayList<>();
        for (int i = 0; i < numRows; i++) {
            rows.add(new StringBuilder());
        }
        int i = 0, flag = -1;
        for (char c : s.toCharArray()) {
            rows.get(i).append(c);
            if (i == 0 || i == numRows - 1) {
                flag = -flag;
            }
            i += flag;
        }
        StringBuilder ans = new StringBuilder();
        for (StringBuilder row : rows) {
            ans.append(row.toString());
        }
        return ans.toString();
    }
}