leetcode 840. 矩陣中的幻方

【題目】840. 矩陣中的幻方

3 x 3 的幻方是一個填充有從 1 到 9 的不同數字的 3 x 3 矩陣,其中每行,每列以及兩條對角線上的各數之和都相等。
給定一個由整數組成的 grid,其中有多少個 3 × 3 的 “幻方” 子矩陣?(每個子矩陣都是連續的)。

示例:

輸入: [[4,3,8,4],
      [9,5,1,9],
      [2,7,6,2]]
輸出: 1
解釋: 
下面的子矩陣是一個 3 x 3 的幻方:
438
951
276

而這一個不是:
384
519
762

總的來說,在本示例所給定的矩陣中只有一個 3 x 3 的幻方子矩陣。

提示:
1 <= grid.length <= 10
1 <= grid[0].length <= 10
0 <= grid[i][j] <= 15=

【解題思路1】按定義

可以在代碼中添加 if grid[r+1][c+1] != 5: continue,幫助我們略過一些循環:

  • 網格的總和是 45,因爲網格必須是 1 到 9 不同的數字。
  • 每一列和行加起來必須是 15,乘以 3 則是網格的總和。
  • 對角線的和也必須是 15,題目中說了對角線與列,行的和相同。
  • 將四條穿過中心的線的 12 個值相加(即一行一列兩條對角線),這四條線加起來等於 60;而整個網
  • 格加起來爲 45。則中心等於 (60-45)/3 = 5
class Solution {
    public int numMagicSquaresInside(int[][] grid) {
        int R = grid.length, C = grid[0].length;
        int ans = 0;
        for (int r = 0; r < R-2; ++r)
            for (int c = 0; c < C-2; ++c) {
                if (grid[r+1][c+1] != 5) continue;
                if (magic(grid[r][c], grid[r][c+1], grid[r][c+2],
                          grid[r+1][c], grid[r+1][c+1], grid[r+1][c+2],
                          grid[r+2][c], grid[r+2][c+1], grid[r+2][c+2]))
                    ans++;
            }

        return ans;
    }

    public boolean magic(int... vals) {
        int[] count = new int[16];
        for (int v: vals) count[v]++;
        for (int v = 1; v <= 9; ++v)
            if (count[v] != 1)
                return false;

        return (vals[0] + vals[1] + vals[2] == 15 &&
                vals[3] + vals[4] + vals[5] == 15 &&
                vals[6] + vals[7] + vals[8] == 15 &&
                vals[0] + vals[3] + vals[6] == 15 &&
                vals[1] + vals[4] + vals[7] == 15 &&
                vals[2] + vals[5] + vals[8] == 15 &&
                vals[0] + vals[4] + vals[8] == 15 &&
                vals[2] + vals[4] + vals[6] == 15);
    }
}

【解題思路2】抽屜算法

另一種分析
滿足幻方的條件必定是中間的數字爲5,周圍的數字爲滿足 1->6->7->2->9->4->3->8->1
的這種圓環結構,5的上下左右必定是 1、9、3、7(這四個數字都只能組成兩組 15)
並且5的周圍的數字其實都可以跳過,這裏沒作實現
1.利用數組的索引語義記錄索引對應的下一個數字
2.若5的下一個值滿足條件,且該值的下一行對應列滿足條件,順時針
若5的下一個值滿足條件,且該值的上一行對應列滿足條件,逆時針
3.總共判斷6次即可(前兩次已經判斷過了)

class Solution {
    public int numMagicSquaresInside(int[][] grid) {
        //if(grid == null || grid.length < 3 || grid[1].length < 3)return 0;
        //由於是1~9的不同數字,那麼必定是5在中間,並且其他數字滿足順時針或逆時針
        int[] check = {0,6,9,8,3,0,7,2,1,4};
        int result = 0;
        for(int i=1;i<grid.length-1;i++){
            for(int j=1;j<grid[0].length-1;j++){
                if(grid[i][j] == 5){
                    int next = grid[i][j+1];
                    switch(next){
                        case 1:
                        case 3:
                        case 7:
                        case 9:
                            if(check[next] == grid[i+1][j+1]){
                                if(each(grid,check,i+1,j+1,1))
                                    result++;
                            }else if(check[next] == grid[i-1][j+1]){
                                if(each(grid,check,i-1,j+1,-1))
                                    result++;
                            }
                    }
                    //5的後一位必定不用算    
                    j++;
                }
            }
        }
        return result;
    }

    public boolean each(int[][] grid,int[] check,int x,int y,int ward){
        int cur = grid[x][y];
        int next = check[cur];
        for(int i=y-2;y!=i;){
            if(grid[x][--y] != next)
                return false;
            cur = next;
            next = check[cur];
        }
        for(int i=x-2*ward;x!=i;){
            if(grid[x-=ward][y] != next)
                return false;
            cur = next;
            next = check[cur];
        }
        for(int i=y+2;y!=i;){
            if(grid[x][++y] != next)
                return false;
            cur = next;
            next = check[cur];
        }
        return true;       
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章