236 lines
6.3 KiB
Markdown
236 lines
6.3 KiB
Markdown
# Leetcode Valid-Sodoku
|
||
|
||
#### 2022-06-13 12:56
|
||
|
||
---
|
||
##### Data structures:
|
||
#DS #vector
|
||
##### Difficulty:
|
||
#leetcode #coding_problem #difficulty-easy
|
||
##### Related topics:
|
||
```expander
|
||
tag:#vector
|
||
```
|
||
|
||
- [[Binary Search Algorithm]]
|
||
- [[cpp_Range_based_for_loop]]
|
||
- [[Leetcode Merge-Sorted-Array]]
|
||
- [[Leetcode Reshape-The-Matrix]]
|
||
- [[Leetcode Search-a-2D-Matrix]]
|
||
|
||
|
||
##### Links:
|
||
- [Link to problem](https://leetcode.com/problems/valid-sudoku/)
|
||
- [Simple solution](https://leetcode.com/problems/valid-sudoku/discuss/15464/My-short-solution-by-C%2B%2B.-O(n2))
|
||
___
|
||
### Problem
|
||
|
||
Determine if a `9 x 9` Sudoku board is valid. Only the filled cells need to be validated **according to the following rules**:
|
||
|
||
1. Each row must contain the digits `1-9` without repetition.
|
||
2. Each column must contain the digits `1-9` without repetition.
|
||
3. Each of the nine `3 x 3` sub-boxes of the grid must contain the digits `1-9` without repetition.
|
||
|
||
**Note:**
|
||
|
||
- A Sudoku board (partially filled) could be valid but is not necessarily solvable.
|
||
- Only the filled cells need to be validated according to the mentioned rules.
|
||
|
||
#### Examples
|
||
![[Pasted image 20220613125739.png]]
|
||
```markdown
|
||
**Input:** board =
|
||
[["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"]]
|
||
**Output:** true
|
||
```
|
||
|
||
```markdown
|
||
**Input:** board =
|
||
[["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"]]
|
||
**Output:** false
|
||
**Explanation:** Same as Example 1, except with the **5** in the top left corner being modified to **8**. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
|
||
```
|
||
|
||
#### Constraints
|
||
|
||
- board.length == 9
|
||
- board[i].length == 9
|
||
- board[i][j] is a digit `1-9` or `'.'`.
|
||
|
||
### Thoughts
|
||
|
||
This should be a follow-up of [[Leetcode Reshape-The-Matrix]], I tried to implement using unordered set, but regular arrays should suffice.
|
||
|
||
Besides overthinking, I also spent a lot of time learning how to use sets and init multi-dimensional vectors.
|
||
|
||
**Take TWO:**
|
||
Use a hash table to store whether an element is present:
|
||
```cpp
|
||
int usedRow[9][10] = {};
|
||
int usedCol[9][10] = {};
|
||
int usedGrid[9][10] = {};
|
||
```
|
||
### Solution
|
||
|
||
My new solution using hash map
|
||
```cpp
|
||
class Solution {
|
||
public:
|
||
bool isValidSudoku(vector<vector<char>> &board) {
|
||
// from 0 to 9
|
||
int usedRow[9][10] = {};
|
||
int usedCol[9][10] = {};
|
||
int usedGrid[9][10] = {};
|
||
int grid;
|
||
int boardVal;
|
||
|
||
for (int i = 0; i < 9; i++) {
|
||
for (int j = 0; j < 9; j++) {
|
||
grid = i / 3 * 3 + j / 3;
|
||
|
||
boardVal = board[i][j];
|
||
if (boardVal == '.') {
|
||
continue;
|
||
}
|
||
boardVal = boardVal - '0';
|
||
|
||
if (usedRow[i][boardVal] || usedCol[j][boardVal] ||
|
||
usedGrid[grid][boardVal]) {
|
||
return false;
|
||
}
|
||
usedRow[i][boardVal]++;
|
||
usedCol[j][boardVal]++;
|
||
usedGrid[grid][boardVal]++;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
};
|
||
```
|
||
|
||
Bad solution :(
|
||
```cpp
|
||
class Solution {
|
||
public:
|
||
bool isValidSudoku(vector<vector<char>> &board) {
|
||
// store info as unordered_set
|
||
// even(it % 2 == 0):
|
||
// horizontal
|
||
// odd(it % 2 == 1):
|
||
// vertical
|
||
vector<vector<vector<unordered_set<int>>>> sets(9);
|
||
for (int i = 0; i < 9; i++) {
|
||
sets[i] = vector<vector<unordered_set<int>>>(2);
|
||
for (int j = 0; j < 2; j++) {
|
||
sets[i][j] = vector<unordered_set<int>>(3);
|
||
}
|
||
}
|
||
|
||
for (int i = 0; i < 9; i++) {
|
||
// populate set[i][0], horizontal
|
||
for (int j = 3 * (i / 3); j < 3 * (i / 3) + 3; j++) { // iterate rows
|
||
for (int k = 3 * (i % 3); k < 3 * (i % 3) + 3;
|
||
k++) { // iterate over cols
|
||
if (board[j][k] >= '0' && board[j][k] <= '9') {
|
||
// Insert that if it is a number
|
||
auto valPair = sets[i][0][j % 3].insert(board[j][k] - '0');
|
||
// there is a duplicate
|
||
if (valPair.second == false) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// if the whole set is empty
|
||
bool is_empty = true;
|
||
for (int j = 0; j < 3; j++) {
|
||
if (!sets[i][0][j].empty()) {
|
||
is_empty = false;
|
||
continue;
|
||
}
|
||
}
|
||
if (is_empty == true) {
|
||
continue;
|
||
}
|
||
|
||
// check sets[i][0][*] is legit, and move data to set[i][0][0]
|
||
unordered_set<int> tmp;
|
||
for (auto tmpsets : sets[i][0]) {
|
||
for (int j : tmpsets) {
|
||
auto result = tmp.insert(j);
|
||
if (result.second == false) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
// populate set[i][0], vertically
|
||
for (int k = 3 * (i % 3); k < 3 * (i % 3) + 3; k++) { // iterate over cols
|
||
for (int j = 3 * (i / 3); j < 3 * (i / 3) + 3; j++) { // iterate rows
|
||
if (board[j][k] >= '0' && board[j][k] <= '9') {
|
||
// Insert that if it is a number
|
||
auto valPair = sets[i][1][k % 3].insert(board[j][k] - '0');
|
||
// there is a duplicate
|
||
if (valPair.second == false) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// check each row and col.
|
||
for (int i = 0; i < 9; i++) {
|
||
for (int k = 0; k < 3; k++) {
|
||
// check for rows
|
||
if (i % 3 != 2) {
|
||
sets[i + 1][0][k].merge(sets[i][0][k]);
|
||
if (!sets[i][0][k].empty()) {
|
||
printf("Found at %d\n", i);
|
||
for (int val : sets[i][0][k]) {
|
||
printf("%d ", val);
|
||
}
|
||
printf("\n");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// check for cols
|
||
if (i < 6) {
|
||
sets[i + 3][1][k].merge(sets[i][1][k]);
|
||
if (!sets[i][1][k].empty()) {
|
||
printf("Found duplicated col at %d, %d\n", i, k);
|
||
for (int val : sets[i][1][k]) {
|
||
printf("%d ", val);
|
||
}
|
||
printf("\n");
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
};
|
||
|
||
```
|