36. 有效的数独Valid Sudoku/37. 解数独

vector里面装bool类型,在<< Effective STL>> 这本书里有说明,最好不要在vector装bool类型。替换本文就好。

const int cnt = 9;
        bool rowFlag[cnt][cnt] = {false};
        bool colFlag[cnt][cnt] = {false};
        bool cellFlag[cnt][cnt] = {false};
36. 有效的数独Valid Sudoku

难度:easy

分析:
我们需要三个标志矩阵,分别记录各行,各列,各小方阵是否出现某个数字,
其中行和列标志下标很好对应,就是cell小方阵的下标需要稍稍转换一下。

if (rowFlag[i][c] || colFlag[c][j] || cellFlag[3 * (i / 3) + j / 3][c])
其实也就是满足三条:

  • 1.数字 1-9 在每一行只能出现一次。
  • 2.数字 1-9 在每一列只能出现一次。
  • 3.数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

[3 * (i / 3) + j / 3]画个图代表每一个小方阵从左到右,从上到下。
在这里插入图片描述

class Solution {
 public:
	 bool isValidSudoku(vector<vector<char>>& board) {
		 if (board.empty() || board[0].empty())return false;
		 int m = board.size(), n = board[0].size();
		 vector < vector<bool >>rowFlag(m, vector<bool>(n, false));
		 vector < vector<bool >>colFlag(m, vector<bool>(n, false));
		 vector < vector<bool >>cellFlag(m, vector<bool>(n, false));
		 for(int i=0;i<m;i++)
			 for (int j = 0; j < n; j++)
			 {
				 if (board[i][j] >= '1'&& board[i][j] <= '9')
				 {
					 int c = board[i][j] - '1';
					 if (rowFlag[i][c] || colFlag[c][j] || cellFlag[3 * (i / 3) + j / 3][c])
						 return false;
					 rowFlag[i][c] = true;
					 colFlag[c][j] = true;
					 cellFlag[3 * (i / 3) + j / 3][c] = true;
				 }
			 }
		 return true;
	 }
 };
37. 解数独,代码参考[2]

难度:hard
跟此题类似的
有 Permutations 全排列,
Combinations 组合项,
N-Queens N皇后问题等等,
其中尤其是跟 N-Queens N皇后问题的解题思路及其相似.

c++ code:

 class Solution {
 public:
	 bool rowFlag[9][9];
	 bool colFlag[9][9];
	 bool cellFlag[9][9];
	 void solveSudoku(vector<vector<char>>& board) {
		 if (board.size() != 9 || board[0].size() != 9)return;
		 int m = board.size(), n = board[0].size();
		 int c;	      
		 for (int i = 0; i<m; i++)//初始化
			 for (int j = 0; j < n; j++)
			 {
				 if (board[i][j] == '.')continue;
				 c = board[i][j] - '1';
				 rowFlag[i][c] = true;
				 colFlag[c][j] = true;
				 cellFlag[3 * (i / 3) + j / 3][c] = true;
			 }
		 DFsolve(board,0);
	 }
	 bool DFsolve(vector<vector<char>>& board,int pos)
	 {
		 int row = pos / 9;
		 int col = pos % 9;
		 if (pos > 80)return true;//finish

		 if (board[row][col] != '.')
		 {
			 return DFsolve(board,pos + 1);
		 }
		 for (int c = 0; c < 9; c++)
		 {
			 if (rowFlag[row][c] || colFlag[c][col] || cellFlag[3 * (row / 3) + col / 3][c])
				 continue;//找到满足的number
			 board[row][col] = (char)(c + '1');
			 rowFlag[row][c] = colFlag[c][col] = cellFlag[3 * (row / 3) + col / 3][c] = true;
			 if (DFsolve(board, pos + 1))
				 return true;
			 else
			 {//重新找
				 board[row][col] = '.';
				 rowFlag[row][c] = colFlag[c][col] = cellFlag[3 * (row / 3) + col / 3][c] = false;
			 }

		 }
		 return false;
	 }
 };

[1]https://segmentfault.com/a/1190000004309465
[2]https://segmentfault.com/a/1190000000457789

### 使用Java实现解数独算法 #### 数独求解的技术概述 数独是一种基于逻辑推理的游戏,目标是在9×9网格中填入数字1到9,使得每一行、每一列以及每一个3×3子网格内的数字均不重复。为了有效解决这个问题,在编程实践中通常采用回溯法或深度优先搜索(DFS)[^1]。 #### Java中的解数独方法 下面展示了一个完整的Java程序用于解答数独谜题: ```java public class SudokuSolver { public void solveSudoku(char[][] board) { backtrack(board, 0, 0); } private boolean backtrack(char[][] board, int r, int c) { if (c == 9) { // 当前列已满,则转至下一行首部 return backtrack(board, r + 1, 0); } if (r == 9) { // 所有行都已完成填充则返回成功标志 return true; } if (board[r][c] != '.') { // 如果当前位置已有数值跳过此位置继续尝试下一个单元格 return backtrack(board, r, c + 1); } for (char num = '1'; num <= '9'; ++num) { // 尝试放置'1'-‘9’之间的任意字符作为候选值 if (!isValid(board, r, c, num)) continue; // 若违反规则立即停止当前循环 board[r][c] = num; // 做选择并标记该位已被占用 if (backtrack(board, r, c + 1)) return true; board[r][c] = '.'; // 取消选择以便后续其他可能性测试 } return false; } private boolean isValid(char[][] board, int r, int c, char n) { for (int i = 0; i < 9; ++i) { if (board[r][i] == n || board[i][c] == n || board[(r/3)*3+i/3][(c/3)*3+i%3] == n) return false; } return true; } } ``` 上述代码定义了解决数独问题所需的`solveSudoku()`函数及其辅助函数`backtrack()`. `backtrack()`负责递归地寻找解决方案;而`isValid()`用来验证给定的位置上设置特定数字是否合法[^5].
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值