1. 程式人生 > >乘風破浪:LeetCode真題_006_ZigZag Conversion

乘風破浪:LeetCode真題_006_ZigZag Conversion

 乘風破浪:LeetCode真題_006_ZigZag Conversion

一、前言

   到這裡我們對基本的問題有了一定的理解,其中字串的操作一直是一個比較困難的問題,這一點我們需要認真對待,採用合理的方案去解決問題。下面我們就看看將字串按照某種格式排列之後再按行輸出的問題。

二、ZigZag Conversion

2.1 問題理解

 

2.2 分析以解決問題

    看到這樣的問題我們最直接的想法就是構造一個二維陣列,初始化成某種字元,然後按照題目給定的規則進行填充,填充完成之後按行進行遍歷,將結果拼湊起來輸出出去。這種方法複雜度為O(n~2)。因此我們進行優化,採用StringBuilder這樣的結構來直接進行儲存,能夠將時間複雜度縮小到O(n)。

    下面是官方的解法:

 1 class Solution {
 2     public String convert(String s, int numRows) {
 3 
 4         if (numRows == 1) return s;
 5 
 6         List<StringBuilder> rows = new ArrayList<>();
 7         for (int i = 0; i < Math.min(numRows, s.length()); i++)
8 rows.add(new StringBuilder()); 9 10 int curRow = 0; 11 boolean goingDown = false; 12 13 for (char c : s.toCharArray()) { 14 rows.get(curRow).append(c); 15 if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown; 16 curRow += goingDown ? 1 : -1;
17 } 18 19 StringBuilder ret = new StringBuilder(); 20 for (StringBuilder row : rows) ret.append(row); 21 return ret.toString(); 22 } 23 }

   我們的演算法:

public class Solution {
    /**
     * 題目大意
     * 輸入一個字串和指定的行數,將字元以Z字型輸出。
     *
     * 解題思路
     * 計算出字元的最大列數,根據列數和行數建立一個一維陣列,再計算每個字元中一維陣列中的位置,
     * 再對一維陣列中的字元進行緊湊操作,返回結果。
     * </pre>
     *
     * @param s
     * @param nRows
     * @return
     */
    public String convert(String s, int nRows) {

        if (s == null || s.length() <= nRows || nRows == 1) {
            return s;
        }

        int index = s.length();
        int rowLength = 0; // 計算行的長度,包括最後換行字元

        int slash = nRows - 2; // 一個斜線除去首尾所佔用的行數

        while (index > 0) {
            // 豎形的一列
            index -= nRows;
            rowLength++;

            // 斜著的列數
            for (int i = 0; i < slash && index > 0; i++) {
                rowLength++;
                index--;
            }
        }

        char[] result = new char[nRows * rowLength]; // 儲存結果的陣列,最後一列用於儲存換行符
        for (int i = 0; i < result.length; i++) { // 初始化為空格
            result[i] = ' ';
        }

        int curColumn = 0; // 當前處理的行數
        index = 0;
        while (index < s.length()) {
            // 處理豎線
            for (int i = 0; i < nRows && index < s.length(); i++) {
                result[rowLength * i + curColumn] = s.charAt(index);
                index++;
            }
            curColumn++;
            // 處理斜線
            for (int i = nRows - 2; i > 0 && index < s.length(); i--) {
                result[rowLength * i + curColumn] = s.charAt(index);
                curColumn++;
                index++;
            }
        }

        // 對字元陣列進行緊湊操作
        index = 0;
        while (index < s.length() && result[index] != ' ') { // 找第一個是空格的字元位置
            index++;
        }
        int next = index + 1;
        while (index < s.length()) {
            while (next < result.length && result[next] == ' ') { // 找不是空格的元素
                next++;
            }
            result[index] = result[next];
            index++;
            next++;
        }
        return new String(result, 0, index);
    }
}

    這樣的演算法其實就是笨辦法了,首先計算出虛擬的二維陣列需要的空間大小,然後實際上(物理上)用一維陣列來表示,並且初始化為空,之後將源字串的字元按照規則填到虛擬的二維陣列中,其實是一維陣列,最後將一維陣列中的空格去除掉就得到了想要的結果,顯然是一個O(n~2)的演算法,沒有官方的好。

三、總結

    通過這樣的一個例子,我們可以發現往往我們的原始想法都是暴力法,按部就班的來,只要稍微的優化一下就能變成更好的方法,得到更優質的結果,寫更少的程式碼。