notes/OJ notes/pages/Leetcode Valid-Sudoku.md
2022-07-07 21:24:34 +08:00

234 lines
6.3 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Leetcode Valid-Sodoku
#### 2022-06-13 12:56
---
##### Data structures:
#DS #vector
##### Difficulty:
#leetcode #coding_problem #difficulty-easy
##### Related topics:
```expander
tag:#vector
```
- [[cpp_Range_based_for_loop]]
- [[Leetcode Merge-Sorted-Array]]
- [[Leetcode Reshape-The-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;
}
};
```