leetcode:Sudoku Solver

Sudoku Solver

题目连接:https://oj.leetcode.com/problems/sudoku-solver/
runtimes:15ms

一、问题

Write a program to solve a Sudoku puzzle by filling the empty cells. 
Empty cells are indicated by the character '.'. 
You may assume that there will be only one unique solution.
                   
 A sudoku puzzle...                                                                   ...and its solution numbers marked in red.

二、分析

              数独问题的规则是每一行,每一列,每一宫的9个格是1-9的序列,没有重复。因此传统的思路是逐一扫描,往一个格填入一个数,判断是否合法,合法就继续下一个格,不合法就继续下一个数。比如我们从左至右,从上至下扫描,遇到R1C3(第一行第三列),填入1-3发现都不符合,因此继续尝试4,发现满足要求,于是继续填入R1C4,以此类推,依次完成剩下的空格。


三、小结

              以上分析是传统的回溯算法思想。回溯算法代码比较固定,以下给出非递归和递归两种方案。
              其中我用了rowState、colState、palaState来记录行、列、宫的数字使用情况,用record来记录空格坐标。
              

四、方案

非递归方案的实现:
#include<iostream>
#include<vector>
using namespace std;

class Solution {
	
public:
	void solveSudoku(vector<vector<char> > &board) {
		const int place[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
		bool rowState[9][9], colState[9][9], palaState[9][9];
		int record[81][2], counter = 0;
		for (int i = 0; i < 9; i++)
		{
			for (int j = 0; j < 9; j++)
			{
				rowState[i][j] = colState[i][j] = palaState[i][j] = false;
			}
		}
		for (int i = 0; i < board.size(); i++)
		{
			for (int j = 0; j < board[i].size(); j++)
			{
				if (board[i][j] != '.')
				{
					rowState[i][board[i][j] - '1'] = true;
					colState[j][board[i][j] - '1'] = true;
					palaState[place[i / 3][j / 3] - 1][board[i][j] - '1'] = true;
				}
				else{
					record[counter][0] = i;
					record[counter][1] = j;
					counter++;
				}
			}
		}
		int i = 0, j = 0, k = 1;
		vector <int> kVec; //kVec.push_back(k);
		while (i < counter)
		{
			
			while (k < 10)
			{
				if (i < counter && !rowState[record[i][0]][k - 1] && !colState[record[i][1]][k - 1] && !palaState[place[record[i][0] / 3][record[i][1] / 3] - 1][k - 1])
				{
					board[record[i][0]][record[i][1]] = k + '0';
					rowState[record[i][0]][k - 1] = true;
					colState[record[i][1]][k - 1] = true;
					palaState[place[record[i][0] / 3][record[i][1] / 3] - 1][k - 1] = true;
					i++; 
					kVec.push_back(k);
					k = 1;
				}
				else{
					k++;
				}
			}
			if (i >= counter)
			{
				for (int i = 0; i < board.size(); i++)
				{
					for (int j = 0; j < board.size(); j++)
					{
						cout << board[i][j] << " ";
					}
					cout << endl;
				}
				return ;
			}
			else{
				i--; k = kVec.back(); kVec.pop_back();
				board[record[i][0]][record[i][1]] = '.';
				rowState[record[i][0]][k - 1] = false;
				colState[record[i][1]][k - 1] = false;
				palaState[place[record[i][0] / 3][record[i][1] / 3] - 1][k - 1] = false;
				k++;
			}
		}
	}
};

int main(int argc, char **argv[])
{
	char b[9][9] = { 
	{ '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' } };
	vector <vector <char> > board(9, vector<char>(9, '.'));
	for (int i = 0; i < 9; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			board[i][j] = b[i][j];
		}
	}
	Solution s;
	s.solveSudoku(board);
	return 0;
}




递归方案的实现:
class Solution {
	
public:
	bool DS(vector<vector<char> > &board, int i, const int place[3][3], bool rs[9][9], bool cs[9][9], bool ps[9][9], int re[81][2], int co)
	{
		if (i < co)
		{
			for (int k = 1; k < 10; k++)
			{
				if (!rs[re[i][0]][k - 1] && !cs[re[i][1]][k - 1] && !ps[place[re[i][0] / 3][re[i][1] / 3] - 1][k - 1])
				{
					board[re[i][0]][re[i][1]] = k + '0';
					rs[re[i][0]][k - 1] = true;
					cs[re[i][1]][k - 1] = true;
					ps[place[re[i][0] / 3][re[i][1] / 3] - 1][k - 1] = true;
					if (DS(board, i + 1, place, rs, cs, ps, re, co))
					{
						return true;
					}
					else{
						board[re[i][0]][re[i][1]] = '.';
						rs[re[i][0]][k - 1] = false;
						cs[re[i][1]][k - 1] = false;
						ps[place[re[i][0] / 3][re[i][1] / 3] - 1][k - 1] = false;
					}
				}
			}
			return false;
		}
		else{
			return true;
		}
	}

	void solveSudoku(vector<vector<char> > &board) {
		const int place[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
		bool rowState[9][9], colState[9][9], palaState[9][9];
		int record[81][2], counter = 0;
		for (int i = 0; i < 9; i++)
		{
			for (int j = 0; j < 9; j++)
			{
				rowState[i][j] = colState[i][j] = palaState[i][j] = false;
			}
		}
		for (int i = 0; i < board.size(); i++)
		{
			for (int j = 0; j < board[i].size(); j++)
			{
				if (board[i][j] != '.')
				{
					rowState[i][board[i][j] - '1'] = true;
					colState[j][board[i][j] - '1'] = true;
					palaState[place[i / 3][j / 3] - 1][board[i][j] - '1'] = true;
				}
				else{
					record[counter][0] = i;
					record[counter][1] = j;
					counter++;
				}
			}
		}
		if (DS(board, 0, place, rowState, colState, palaState, record, counter))
		{
			for (int i = 0; i < board.size(); i++)
			{
				for (int j = 0; j < board.size(); j++)
				{
					cout << board[i][j] << " ";
				}
				cout << endl;
			}
			return;
		}
	}
};







五、三思

        这里有两种方法判断board是否合法,第一种就是每次填完数循环扫描行、列、宫,看是否合法,明显酱紫花时间,我的代码用空间换空间,将O(3*9)降到O(3),即更新了每次行、列、宫使用数字的情况,而不用循环扫描。

       这篇文章写得还不错,可以参考:http://www.cnblogs.com/zhaolizhen/p/Sudoku.html



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值