notes/OJ notes/pages/Leetcode Valid-Sudoku.md

236 lines
6.3 KiB
Markdown
Raw Normal View History

2022-06-14 23:33:35 +08:00
# Leetcode Valid-Sodoku
#### 2022-06-13 12:56
---
##### Data structures:
#DS #vector
##### Difficulty:
#leetcode #coding_problem #difficulty-easy
##### Related topics:
```expander
tag:#vector
```
2022-07-10 08:29:59 +08:00
- [[Binary Search Algorithm]]
2022-06-14 23:33:35 +08:00
- [[cpp_Range_based_for_loop]]
- [[Leetcode Merge-Sorted-Array]]
- [[Leetcode Reshape-The-Matrix]]
2022-07-10 08:29:59 +08:00
- [[Leetcode Search-a-2D-Matrix]]
2022-06-14 23:33:35 +08:00
##### 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.
2022-06-29 09:05:26 +08:00
**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] = {};
```
2022-06-14 23:33:35 +08:00
### Solution
2022-06-29 09:05:26 +08:00
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;
}
};
```
2022-06-14 23:33:35 +08:00
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;
}
};
```