2021-11-02 Daily-Challenge
Today I have done leetcode's November LeetCoding Challenge with cpp
.
November LeetCoding Challenge 2
Description
Unique Paths III
You are given an m x n
integer array grid
where grid[i][j]
could be:
1
representing the starting square. There is exactly one starting square.2
representing the ending square. There is exactly one ending square.0
representing empty squares we can walk over.-1
representing obstacles that we cannot walk over.
Return the number of 4-directional walks from the starting square to the ending square, that walk over every non-obstacle square exactly once.
Example 1:
Input: grid = [[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
Output: 2
Explanation: We have the following two paths:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)
Example 2:
Input: grid = [[1,0,0,0],[0,0,0,0],[0,0,0,2]]
Output: 4
Explanation: We have the following four paths:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)
3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)
4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)
Example 3:
Input: grid = [[0,1],[2,0]]
Output: 0
Explanation: There is no path that walks over every empty square exactly once.
Note that the starting and ending square can be anywhere in the grid.
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 20
1 <= m * n <= 20
-1 <= grid[i][j] <= 2
- There is exactly one starting cell and one ending cell.
Solution
const char moves[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
class Solution {
char rows;
char cols;
char start;
char finish;
char obstacles;
char target;
char answer;
unordered_set<string> cache;
vector<bool> visit;
string path;
void init(vector<vector<int>> &grid) {
rows = grid.size();
cols = grid.front().size();
for(int i = 0; i < rows; ++i) {
for(char j = 0; j < cols; ++j) {
switch(grid[i][j]) {
case 1:
start = i * cols + j;
break;
case 2:
finish = i * cols + j;
break;
case -1:
obstacles += 1;
default:
;
}
}
}
target = rows * cols - obstacles;
}
bool checkConnection(vector<vector<int>>& grid) {
queue<pair<char, char>> q;
bool vis[rows][cols];
memset(vis, 0, sizeof(vis));
vis[start / cols][start % cols] = true;
q.push({start / cols, start % cols});
while(q.size()) {
auto [row, col] = q.front();
if(row * cols + col == finish) return true;
q.pop();
for(char i = 0 ; i < 4; ++i) {
char newRow = row + moves[i][0];
char newCol = col + moves[i][1];
if(newRow < 0 || newCol < 0 || newRow >= rows || newCol >= cols) continue;
if(vis[newRow][newCol] || grid[newRow][newCol] == -1) continue;
vis[newRow][newCol] = true;
q.push({newRow, newCol});
}
}
return false;
}
void solve(vector<vector<int>>& grid) {
if(cache.count(path)) return;
cache.insert(path);
// cout << ToHex(path) << endl;
char row = path.back() / cols;
char col = path.back() % cols;
if(path.back() == finish) {
answer += path.length() == target;
return;
}
for(char i = 0; i < 4; ++i) {
char newRow = row + moves[i][0];
char newCol = col + moves[i][1];
if(newRow < 0 || newCol < 0 || newRow >= rows || newCol >= cols) continue;
if(visit[newRow * cols + newCol] || grid[newRow][newCol] == -1) continue;
visit[newRow * cols + newCol] = true;
path.push_back(newRow * cols + newCol);
solve(grid);
path.pop_back();
visit[newRow * cols + newCol] = false;
}
}
public:
int uniquePathsIII(vector<vector<int>>& grid) {
init(grid);
if(!checkConnection(grid)) {
return 0;
}
unordered_set<string> cache;
visit.resize(rows * cols);
path.push_back(start);
visit[start] = true;
solve(grid);
return answer;
}
};
// Accepted
// 39/39 cases passed (8 ms)
// Your runtime beats 32.66 % of cpp submissions
// Your memory usage beats 22.59 % of cpp submissions (10 MB)
and do some optimization
const char moves[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
class Solution {
char rows;
char cols;
char start;
char finish;
char obstacles;
char target;
char answer;
char count = 1;
void init(vector<vector<int>> &grid) {
rows = grid.size();
cols = grid.front().size();
for(int i = 0; i < rows; ++i) {
for(char j = 0; j < cols; ++j) {
switch(grid[i][j]) {
case 1:
start = i * cols + j;
break;
case 2:
finish = i * cols + j;
break;
case -1:
obstacles += 1;
default:
;
}
}
}
target = rows * cols - obstacles;
}
void solve(vector<vector<int>>& grid, char pos) {
// cout << ToHex(path) << endl;
char row = pos / cols;
char col = pos % cols;
if(pos == finish) {
answer += count == target;
return;
}
grid[row][col] = -1;
for(char i = 0; i < 4; ++i) {
char newRow = row + moves[i][0];
char newCol = col + moves[i][1];
if(newRow < 0 || newCol < 0 || newRow >= rows || newCol >= cols) continue;
if(grid[newRow][newCol] == -1) continue;
count += 1;
solve(grid, newRow * cols + newCol);
count -= 1;
}
grid[row][col] = 0;
}
public:
int uniquePathsIII(vector<vector<int>>& grid) {
init(grid);
solve(grid, start);
return answer;
}
};
// Accepted
// 39/39 cases passed (0 ms)
// Your runtime beats 100 % of cpp submissions
// Your memory usage beats 67.27 % of cpp submissions (7.1 MB)