1. 程式人生 > 其它 >LeetCode-0037 解數獨

LeetCode-0037 解數獨

技術標籤:LeetCodeleetcode資料結構演算法

題目

輸入:一個9x9二維字元陣列代表一個數獨,空格子以.表示。
輸出:原地修改該二維字元陣列。

思路

顯然要用回溯。
在回溯的時候需要知道上一步是什麼,因此需要記錄上一步的資訊。
常見的記錄方式有兩種:

  1. 用遞迴,系統堆疊會自動記錄上一步的資訊,函式呼叫結束返回上一步。
  2. 手動記錄。

這裡採用第二種。新建一個數組,陣列元素是空格子的座標,解數獨的過程就是工作指標在陣列中不斷前進或回溯直到陣列尾的過程。

在嘗試填入數字時,總是嘗試當前格子數字的下一個。這裡規定.的下一個數字是1。這樣空格子就會從1開始。如果當前格子的數字是9,說明已經嘗試過1-9當時均不合法,此時需要回溯。

當工作指標沒有指向陣列尾時:
	如果當前指向的數獨位置的填充數字是9:
		工作指標前移,並重置該格子為'.';
	否則嘗試填入下一個數字:
		如果合法:
			工作指標後移,將數字寫入數獨;
		否則:
			將數字寫入數獨,進入下一個迴圈; //嘗試下一個數字

程式碼

class Solution {
private:
    vector<pair<int, int>> path; //記錄路徑
public:
    void solveSudoku(vector<vector<char>>& board) {
        for
(int i = 0; i < 9; ++i) { for (int j = 0; j < 9; ++j) { if (board[i][j] == '.') path.push_back(make_pair(i, j)); } } int idx = 0, n = path.size(); //idx是工作指標 int row, col; //記錄當前指向的格子座標 while (idx < n) row =
path[idx].first; col = path[idx].second; if (board[row][col] == '9') { board[row][col] = '.'; --idx; continue; } //回溯 char att; //嘗試填入的數字 if (board[row][col] == '.') att = '1'; else att = board[row][col] + 1; //判斷填入的數字是否合法,合法則工作指標後移 if (isValid(att, row, col, board)) ++idx; //無論是否合法,都將其寫入(不合法時作為上次失敗嘗試的記錄,以便開始下一次嘗試) board[row][col] = att; } } bool isValid(char att, int row, int col, vector<vector<char>>& board) { //小九宮格的起止位置,左閉右開 int row_end = (row / 3 + 1) * 3, col_end = (col / 3 + 1) * 3; //判斷小九宮格內是否合法 for (int i = row / 3 * 3; i < row_end; ++i) { for (int j = col / 3 * 3; j < col_end; ++j) { if (att == board[i][j]) return false; } } //判斷該行是否合法 for (int j = 0; j < 9; ++j) { if (att == board[row][j]) return false; } //判斷該列是否合法 for (int i = 0; i < 9; ++i) { if (att == board[i][col]) return false; } //均無不合法,返回true return true; } };