1. 程式人生 > 其它 >C++string容器-字串查詢和替換

C++string容器-字串查詢和替換

技術標籤:LeetCode

36. 有效的數獨

題目描述

判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。

  1. 數字 1-9 在每一行只能出現一次。

  2. 數字 1-9 在每一列只能出現一次。

  3. 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。

在這裡插入圖片描述
上圖是一個部分填充的有效的數獨。

數獨部分空格內已填入了數字,空白格用 '.' 表示。

示例1:

輸入:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
輸出: true

示例2:

輸入:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
輸出: false
解釋: 除了第一行的第一個數字從 5 改為 8 以外,空格內其他數字均與 示例1 相同。
     但由於位於左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。

說明:

  • 一個有效的數獨(部分已被填充)不一定是可解的。
  • 只需要根據以上規則,驗證已經填入的數字是否有效即可。
  • 給定數獨序列只包含數字 1-9 和字元 '.'
  • 給定數獨永遠是 9x9 形式的。

題解:

法一:

使用三個二維陣列,row[9][9], col[9][9], blo[9][9] ,分別記錄 行、列、塊 中每個元素的狀態。

塊的下標可以用 (i / 3) * 3 + j / 3 來表示。

二重迴圈遍歷 board ,對於填充了數字的格子進行判斷即可。

法一程式碼:

class Solution {
public:
    bool isValidSudoku(vector<vector<
char>>& board) { vector<vector<bool>> row(9, vector<bool>(9, 0) ); vector<vector<bool>> col(9, vector<bool>(9, 0) ); vector<vector<bool>> blo(9, vector<bool>(9, 0) ); int u, k; for ( int i = 8; i >= 0; --i ) { for ( int j = 8; j >= 0; --j ) { if ( board[i][j] == '.' ) continue; u = (board[i][j] & 15) - 1; if ( row[i][u] ) return false; if ( col[j][u] ) return false; k = (i / 3) * 3 + j / 3; if ( blo[k][u] ) return false; row[i][u] = col[j][u] = blo[k][u] = true; } } return true; } }; /* 時間:16ms,擊敗:99.81% 記憶體:18.9MB,擊敗:37.29% */
法二:

其實法一中的陣列第二維用來記錄 1-9 是否出現過,而我們可以使用位運算來優化。

考慮使用一個整數 num ,初值為 0 ,假設當前數字為 9 ,那麼 cnt |= 1 << 9 ,也就是把二進位制中的相應位設定為 1 。這樣可以優化掉 法一 中的第二維。

法二程式碼:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        vector<int> row(9, 0);
        vector<int> col(9, 0);
        vector<int> blo(9, 0);
        int u, k;
        for ( int i = 8; i >= 0; --i ) {
            for ( int j = 8; j >= 0; --j ) {
                if ( board[i][j] == '.' ) continue;
                u = board[i][j] & 15;
                if ( row[i] >> u & 1 ) return false;
                if ( col[j] >> u & 1 ) return false;
                k = (i / 3) * 3 + j / 3;
                if ( blo[k] >> u & 1 ) return false;
                row[i] |= (1 << u);
                col[j] |= (1 << u);
                blo[k] |= (1 << u);
            }
        }
        return true;
    }
};
/*
時間:20ms,擊敗:99.12%
記憶體:17.5MB,擊敗:99.03%
*/

法三:

法二中還可以進行優化,只使用一個數組,將陣列中的前 9 位記錄行的狀態,中間 9 位記錄列的狀態,後面 9 位記錄塊的狀態。int 能夠表示的下。

法三程式碼:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        vector<int> rec(9, 0);
        int u, k;
        int r, c, b;
        for ( int i = 8; i >= 0; --i ) {
            for ( int j = 8; j >= 0; --j ) {
                if ( board[i][j] == '.' ) continue;
                u = board[i][j] & 15;
                r = 1 << u;
                if ( rec[i] & r ) return false;
                c = 1 << 9 << u;
                if ( rec[j] & c ) return false;
                b = 1 << 18 << u;
                k = (i / 3) * 3 + j / 3;
                if ( rec[k] & b ) return false;
                rec[i] |= r;
                rec[j] |= c;
                rec[k] |= b;
            }
        }
        return true;
    }
};
/*
時間:16ms,擊敗:99.81%
記憶體:17.6MB,擊敗:96.58%
*/

優化好像不大2333