C++string容器-字串查詢和替換
阿新 • • 發佈:2021-02-01
技術標籤:LeetCode
36. 有效的數獨
題目描述
判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。
-
數字
1-9
在每一行只能出現一次。 -
數字
1-9
在每一列只能出現一次。 -
數字
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