LintCode 374 螺旋矩陣的解決方法

最近在開心刷LintCode,其實我覺得刷題的目的就是鍛鍊你的解決問題的能力,不同的思想會帶來不同的解決方案,找到最好的那個就是程序員的工作。但在找到最好的之前,你至少需要一點思想。

題目梗概

給定一個包含 m x n 個要素的矩陣,(m 行, n 列),按照螺旋順序,返回該矩陣中的所有要素

[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]

應返回:

[1,2,3,6,9,8,7,4,5]

想法一

既然是這類題目肯定是不能N個for循環去做了,螺旋地把矩陣轉化成鏈表,其步驟一共就四步:向左->向下->向右->向上,然後再進行循環。那麼我們只需要定義出這四個函數,同時在每個函數內判斷出啥時候該轉彎(邊際條件)就行了。

代碼:

public class Solution {
    /**
     * @param matrix a matrix of m x n elements
     * @return an integer list
     */
    public List<Integer> spiralOrder(int[][] matrix) {
        // Write your code here
        List<Integer> ret = new ArrayList<Integer>() ;
        if(matrix.length == 0)
        {
            return ret;
        }
        int size = (matrix.length) *(matrix[0].length);
        int n = 1;
        while(ret.size() != size)
        {
            ret.addAll(onesplit(matrix , n));
            ret.addAll(twosplit(matrix , n));
            ret.addAll(threesplit(matrix ,n));
            ret.addAll(foursplit(matrix , n));
            n++;
        }
        return ret;

    }
    public List<Integer> onesplit(int [][] matrix , int n) { //(0,0) - > (0,4)
        List<Integer> ret = new ArrayList<Integer>() ;
        int limit = matrix[0].length -n + 1;
        for (int i = n-1 ; i < limit ; i++) {
            ret.add(matrix[n-1][i]);
        }
        return ret;
    }
        public List<Integer> twosplit(int [][] matrix , int n) {//(1,4) - > (4,4)
        List<Integer> ret = new ArrayList<Integer>() ;
        int limit = matrix.length - n + 1 ;
        for (int i = n ; i < limit; i++) {
            ret.add(matrix[i][matrix[0].length - n]);
        }
        return ret;    
    }
        public List<Integer> threesplit(int [][] matrix , int n) { //(4,3) - > (4,0)
        List<Integer> ret = new ArrayList<Integer>() ;
        int start = matrix[0].length - n -1 ;
        for (int i = start; i >= n-1 ; i--) {
            ret.add(matrix[matrix.length - n ][i]);
        }
        return ret;
    }
        public List<Integer> foursplit(int [][] matrix , int n) {//(3,0) - > (1,0)
        List<Integer> ret = new ArrayList<Integer>() ;
        int start = matrix.length - n -1 ;
        for (int i = start; i >= n ; i--) {
            ret.add(matrix[i][n-1]);
        }
        return ret;
    }
}

整體思路就是依次向四個方向走,每次走到該轉向的時候都把這個方向的最長路徑減一,這樣就能走出螺旋了。

想法很好,思考一下複雜度也應該是O(N)吧,但是Submit後給我返回了個“TLE”

既然TLE了,這個算法肯定是不行的,換個思路吧。


想法二

我們還是假裝在一個矩陣上走路,不過現在我們一次只走一格,每走一格我們都去想有沒有走到“頭”,如果到頭了就轉向吧,同時每次轉向將下次走這個方向的“頭”的數值-1

代碼實現如下:

public class Solution {
    /**
     * @param matrix a matrix of m x n elements
     * @return an integer list
     */
    public List<Integer> spiralOrder(int[][] matrix) {
        // Write your code here
        List<Integer> ret = new LinkedList<Integer> ();
        if(matrix.length == 0)
        {
            return ret;
        }
        int m = 0;
        int n = 0;
        int flag = 0;
        int limit_1 = matrix.length -1; //豎着的
        int limit_2 = matrix[0].length -1; //橫着的
        int size = matrix.length * matrix[0].length;
        int limit_3 = 1;//豎着的
        int limit_4 = 0;//橫着的
        while(ret.size()!=size)
        {
            ret.add(matrix[m][n]);

            if(flag == 0){
                //橫着往右走
                if( n == limit_2){
                    flag = 1;
                    limit_2--;
                    m++;
                    continue;
                }
                n++;
            }
            else if(flag == 1){
                //豎着往下走

                if( m == limit_1){
                    flag = 2;
                    limit_1--;
                    n--;
                    continue;

                }
                m++;
            }
            else if(flag == 2){
                //橫着往左走

                if( n == limit_4){
                    flag = 3;
                    limit_4++;
                    m--;
                    continue;
                }
                n--;
            }
            else if(flag == 3){
                //豎着往上走

               if(m == limit_3){
                    flag = 0;
                    limit_3++;
                    n++;
                    continue;
                }
                m--;
            }

        }
        return ret;
    }
}

然後果然AC了,還是蠻開心的,通過把兩個循環拆成一個成功解決了TLE的問題,不過代碼中很多IF判斷其實應該用switch,不夠簡潔。


希望能遇上更多的TLE加深我對算法思路的認識

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章