不同路徑 III
題目
在二維網格 grid
上,有 4
種類型的方格:
1
表示起始方格。且只有一個起始方格。2
表示結束方格,且只有一個結束方格。0
表示我們可以走過的空方格。-1
表示我們無法跨越的障礙。
返回在四個方向(上、下、左、右)上行走時,從起始方格到結束方格的不同路徑的數目,每一個無障礙方格都要通過一次。
示例 1:
輸入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
輸出:2
解釋:我們有以下兩條路徑:
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)
示例 2:
輸入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]
輸出:4
解釋:我們有以下四條路徑:
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)
示例 3:
輸入:[[0,1],[2,0]]
輸出:0
解釋:
沒有一條路能完全穿過每一個空的方格一次。
請注意,起始和結束方格可以位於網格中的任意位置。
函數原型
int uniquePathsIII(int** grid, int gridSize, int* gridColSize){}
grid
:二維數組gridSize
:二維數組的行數gridColSize
:二維數組的列數,但是int*
,所以取值的時候用*gridColSize
邊界判斷
int uniquePathsIII(int** grid, int gridSize, int* gridColSize){
if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
return 0;
}
算法設計:DFS回溯哈密爾頓路徑
思路:這道題就是求【哈密爾頓路徑】。
哈密爾頓路徑:從某個點出發,經過每個頂點一次,且恰好每個頂點都只經過一次。
如旅行時,從入口出發如何不重複的走完所有景點,哈密爾頓路徑就是求這個,只不過這個問題不是求【哈密爾頓路徑】是哪條,而是有幾條。
目前求解哈密爾頓路徑沒啥好的算法,所以只能枚舉了。
int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int visited[20][20] = {0};
// 判斷頂點(x, y)座標是否越界
bool inArea(int x, int y, int R, int C){
return x >= 0 && x < R && y >= 0 && y < C;
}
int DFS(int start, int end, int cnt, int R, int C, int **grid){
/* 一維轉二維 */
int x = start / C;
int y = start % C;
visited[x][y] = 1; // 起點已訪問
cnt --; // 可訪問的點 -1
if( cnt == 0 && start == end ){
visited[x][y] = 0; // 回溯清除標記,爲尋找下一條路作準備
return 1;
}
int ans = 0;
for( int d=0; d<4; d++ ){
int nextx = x + dirs[d][0]; // 更新 x
int nexty = y + dirs[d][1]; // 更新 y
if( inArea(nextx, nexty, R, C) && grid[nextx][nexty] == 0 && !visited[nextx][nexty] )
ans += DFS(nextx * C + nexty, end, cnt, R, C, grid);
}
visited[x][y] = 0;
return ans;
}
int uniquePathsIII(int** grid, int gridSize, int* gridColSize){
if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
return 0;
int R = gridSize; // 行數row
int C = *gridColSize; // 列數col
int cnt = R * C; // 記錄實際要走過的點個數
int start, end; // 記錄起點、終點座標
for( int i=0; i < R; i++ )
for( int j=0; j < C; j++ ){
if( grid[i][j] == 1 ){ // 【起始點】
start = i * C + j; // 二維索引轉一維存儲
grid[i][j] = 0; // 起點也可以走
}else if( grid[i][j] == 2 ){ // 【終止點】
end = i * C + j;
grid[i][j] = 0;
}else if( grid[i][j] == -1 ){ // 【障礙物】
cnt --; // 是障礙物,所以不是實際要走的點
}
}
int ans = DFS(start, end, cnt, R, C, grid);
return ans;
}
優化遞歸接口,減掉不必要的參數。
int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
bool visited[20][20] = {false};
struct _graph{
int ** _grid;
int R;
int C;
int start;
int end;
int cnt;
} g;
bool inArea(int x, int y){ // 判斷頂點(x, y)座標是否越界
return x >= 0 && x < g.R && y >= 0 && y < g.C;
}
int DFS(int start, int cnt){
/* 一維轉二維 */
int x = start / g.C;
int y = start % g.C;
visited[x][y] = true; // 起點已訪問
cnt --; // 可訪問的點 -1
if( cnt == 0 && start == g.end ){
visited[x][y] = false; // 回溯清除標記,爲尋找下一條路作準備
return 1;
}
int ans = 0;
for( int d=0; d<4; d++ ){
int nextx = x + dirs[d][0]; // 更新 x
int nexty = y + dirs[d][1]; // 更新 y
if( inArea(nextx, nexty) && g._grid[nextx][nexty] == 0 && !visited[nextx][nexty] )
ans += DFS(nextx * g.C + nexty, cnt);
}
visited[x][y] = false;
return ans;
}
int uniquePathsIII(int** grid, int gridSize, int* gridColSize){
if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
return 0;
g.R = gridSize; // 行數row
g.C = *gridColSize; // 列數col
g._grid = grid;
g.cnt = g.R * g.C; // 記錄實際要走過的點個數
for( int i=0; i < g.R; i++ )
for( int j=0; j < g.C; j++ ){
if( g._grid[i][j] == 1 ){ // 【起始點】
g.start = i * g.C + j; // 二維索引轉一維存儲
g._grid[i][j] = 0; // 起點也可以走
}else if( g._grid[i][j] == 2 ){ // 【終止點】
g.end = i * g.C + j;
g._grid[i][j] = 0;
}else if( g._grid[i][j] == -1 ){ // 【障礙物】
g.cnt --; // 是障礙物,所以不是實際要走的點
}
}
int ans = DFS(g.start, g.cnt);
return ans;
}
DFS回溯哈密爾頓路徑的複雜度:
- 時間複雜度:
- 空間複雜度:
算法設計:DFS狀態壓縮哈密爾頓路徑
算法設計:DFS記憶化搜索哈密爾頓路徑