力扣36—有效的数独
相关标签:数组、哈希表、矩阵
题意
请你判断一个 9 x 9
的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
- 数字
1-9
在每一行只能出现一次。 - 数字
1-9
在每一列只能出现一次。 - 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。(请参考示例图)
注意:
- 一个有效的数独(部分已被填充)不一定是可解的。
- 只需要根据以上规则,验证已经填入的数字是否有效即可。
- 空白格用
'.'
表示。
解法1—哈希表
按照从左往右,从上到下的顺序遍历board,判断数字是否在对应的行、列和 3x3的box 里出现过。
假设数字的下标为 (i,j),那么该数字出现在第 j/3+(i/3)*3 个box。
C++实现
class Solution
{
public:
bool isValidSudoku(vector<vector<char>>& board)
{
//存储数字在对应的行上是否出现过,默认都是0,代表没有出现过
//第二维度是10,代表下标范围可以出现9
int rows[9][10]={0};
int cols[9][10]={0};
int box[9][10]={0}; //一共有9个box
for(int i=0;i<9;++i)
{
for(int j=0;j<9;++j)
{
if(board[i][j]=='.')
continue;
int num = board[i][j]-'0'; // 字符型数字转化为整形数字
if(rows[i][num]==1) //如果该数字在对应的行上出现过就直接返回false
return false;
if(cols[j][num]==1)
return false;
if(box[j/3+(i/3)*3][num]==1)
return false;
rows[i][num]=1;
cols[j][num]=1;
box[j/3+(i/3)*3][num]=1;
}
}
return true;
}
};
解法2—位运算
二进制 用某一位的1代表这个数字出现过,因为题目存储的数字范围是1~9,所以我们需要9个位来标记数字,而int 的 二进制 是32位,所以足以存储。
初始化时 我们可以用0代表没出现,1代表出现过。
class Solution
{
public:
bool isValidSudoku(vector<vector<char>>& board)
{
/*
//存储数字在对应的行上是否出现过,默认都是0,代表没有出现过
//第二维度是10,代表下标范围可以出现9
int rows[9][10]={0};
int cols[9][10]={0};
int box[9][10]={0}; //一共有9个box
for(int i=0;i<9;++i)
{
for(int j=0;j<9;++j)
{
if(board[i][j]=='.')
continue;
int num = board[i][j]-'0'; // 字符型数字转化为整形数字
if(rows[i][num]==1) //如果该数字在对应的行上出现过就直接返回false
return false;
if(cols[j][num]==1)
return false;
if(box[j/3+(i/3)*3][num]==1)
return false;
rows[i][num]=1;
cols[j][num]=1;
box[j/3+(i/3)*3][num]=1;
}
}
return true;
*/
int rows[9]={0}; //表示每一行中数字是否出现过
int cols[9]={0};
int box[9]={0};
for(int i=0;i<9;++i)
{
for(int j=0;j<9;++j)
{
if(board[i][j]=='.')
continue;
int box_index = j/3+(i/3)*3; //表示当前数字是位于第几个box里面
int num = 1<<(board[i][j]-'0'); //当前数字存储在第几位上
if(rows[i]&num || cols[j]&num || box[box_index]&num)
{
//如果当前数字在对应的行、列、box里出现过,就返回false
return false;
}
rows[i]|=num;
cols[j]|=num;
box[box_index]|=num;
}
}
return true;
}
};
力扣73—矩阵置零
相关标签:数组、哈希表、矩阵
题意
给定一个 m x n
的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地算法。
解法1—使用标记数组
class Solution
{
public:
void setZeroes(vector<vector<int>>& matrix)
{
int m = matrix.size(); //原矩阵行数
int n = matrix[0].size(); //原矩阵列数
vector<bool> rows(m,false);
vector<bool> cols(n,false);
for(int i=0;i<m;++i)
{
for(int j=0;j<n;++j)
{
if(!matrix[i][j])
{
rows[i]=cols[j]=true;
}
}
}
for(int i=0;i<m;++i)
{
for(int j=0;j<n;++j)
{
if(rows[i]||cols[j])
{
matrix[i][j]=0;
}
}
}
}
};
法2—使用两个标记变量
我们可以用矩阵的第一行和第一列代替方法一中的两个标记数组,以达到 O(1) 的额外空间。但这样会导致原数组的第一行和第一列被修改,无法记录它们是否原本包含 0。因此我们需要额外使用两个标记变量分别记录第一行和第一列是否原本包含 0。
class Solution
{
public:
void setZeroes(vector<vector<int>>& matrix)
{
int m = matrix.size(); //原矩阵行数
int n = matrix[0].size(); //原矩阵列数
bool rows0_flag=false; //标记第一行是否有0
bool cols0_flag=false; //标记第一列是否有0
//扫描第一行看有没有0
for(int j=0;j<n;++j)
{
if(matrix[0][j]==0)
{
rows0_flag=true;
break;
}
}
//扫描第一列看有没有0
for(int i=0;i<m;++i)
{
if(matrix[i][0]==0)
{
cols0_flag=true;
break;
}
}
//用第一行、第一列记录,非第一行第一列元素为0的情况
for(int i=1;i<m;++i)
{
for(int j=1;j<n;++j)
{
if(0==matrix[i][j])
{
matrix[i][0]=0;//用第一列记录
matrix[0][j]=0;//用第一行记录
}
}
}
//更改非第一行第一列的元素
for(int i=1;i<m;++i)
{
for(int j=1;j<n;++j)
{
if(matrix[i][0]==0 || matrix[0][j]==0)
{
matrix[i][j]=0;
}
}
}
//判断第一行、第一列是否需要改0
if(rows0_flag)
{
for(int j=0;j<n;++j)
matrix[0][j]=0;
}
if(cols0_flag)
{
for(int i=0;i<m;++i)
matrix[i][0]=0;
}
/*
vector<bool> rows(m,false);
vector<bool> cols(n,false);
for(int i=0;i<m;++i)
{
for(int j=0;j<n;++j)
{
if(!matrix[i][j])
{
rows[i]=cols[j]=true;
}
}
}
for(int i=0;i<m;++i)
{
for(int j=0;j<n;++j)
{
if(rows[i]||cols[j])
{
matrix[i][j]=0;
}
}
}
*/
}
};