UniquePaths
问题描述:给定一个起点和终点,找到一共有多少条满足条件的路径。
Unique Paths I
给定一个矩阵,起点在左上角,终点在右下角。只能向下走或者向右走。 思路:我们当然可以用DFS来做,但是时间复杂度就是
O
(
2
(
M
∗
N
)
)
O(2^{(M*N)})
O ( 2 ( M ∗ N ) ) 。所以我们采用动态规划的方法来做。
转移方程如下:
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
]
[
j
−
1
]
dp[i][j] = dp[i-1][j] + dp[i][j-1]
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] 。 初始化:
d
p
[
0
:
i
]
[
0
]
=
1
,
d
p
[
0
]
[
0
:
j
]
=
1
dp[0:i][0] = 1, dp[0][0:j] = 1
d p [ 0 : i ] [ 0 ] = 1 , d p [ 0 ] [ 0 : j ] = 1 代码:
int uniquePaths ( int m, int n) {
int res = 0 ;
int dp[ m] [ n] ;
for ( int i= 0 ; i< m; i++ ) {
dp[ i] [ 0 ] = 1 ;
}
for ( int j= 0 ; j< n; j++ ) {
dp[ 0 ] [ j] = 1 ;
}
for ( int i= 0 ; i< m; i++ ) {
for ( int j= 0 ; j< n; j++ ) {
if ( i == 0 || j == 0 )
continue ;
dp[ i] [ j] = dp[ i- 1 ] [ j] + dp[ i] [ j- 1 ] ;
}
}
res = dp[ m- 1 ] [ n- 1 ] ;
return res;
}
Unique Paths II
给定一个矩阵,起点在左上方,终点在右下方,路径上还有一些点不能走,用1表示。只能走下或右。计算有多少不同的路径。 思路:还是动态规划的想法,相比于I,我们更改一个条件:如果当前位置不可走,则dp[i][j] =0;
转移方程如下:
d
p
[
i
]
[
j
]
=
(
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
]
[
j
−
1
]
)
∗
(
g
r
i
d
[
i
]
[
j
]
=
=
0
)
dp[i][j] = (dp[i-1][j] + dp[i][j-1]) * (grid[i][j] == 0)
d p [ i ] [ j ] = ( d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] ) ∗ ( g r i d [ i ] [ j ] = = 0 ) 。 初始化
dp[0][0] = grid[0][0] == 0; dp[i][0] = dp[i-1][0] && grid[i][0] == 0 dp[0][j] = dp[0][j-1] && grid[0][j] == 0 代码:
int uniquePathsWithObstacles ( vector< vector< int >> & obstacleGrid) {
int m = ( int ) obstacleGrid. size ( ) ;
if ( m == 0 )
return 0 ;
int n = ( int ) obstacleGrid[ 0 ] . size ( ) ;
long long dp[ m] [ n] ;
memset ( dp, 0 , sizeof ( dp) ) ;
if ( obstacleGrid[ 0 ] [ 0 ] != 0 )
return 0 ;
dp[ 0 ] [ 0 ] = 1 ;
for ( int i= 1 ; i< m; i++ ) {
if ( obstacleGrid[ i] [ 0 ] == 0 && dp[ i- 1 ] [ 0 ] == 1 ) {
dp[ i] [ 0 ] = 1 ;
} else {
dp[ i] [ 0 ] = 0 ;
}
}
for ( int j= 1 ; j< n; j++ ) {
if ( obstacleGrid[ 0 ] [ j] == 0 && dp[ 0 ] [ j- 1 ] == 1 ) {
dp[ 0 ] [ j] = 1 ;
} else {
dp[ 0 ] [ j] = 0 ;
}
}
for ( int i= 1 ; i< m; i++ ) {
for ( int j= 1 ; j< n; j++ ) {
if ( obstacleGrid[ i] [ j] == 0 )
dp[ i] [ j] = dp[ i- 1 ] [ j] + dp[ i] [ j- 1 ] ;
else
dp[ i] [ j] = 0 ;
}
}
return dp[ m- 1 ] [ n- 1 ] ;
}
Unique Paths III
给定一个矩阵,0表示可以走,1表示起点,2表示终点,-1表示障碍物。此时可以向四个方向走。问从起点到终点,将所有可以路过的点路过有且只有一次的走法有多少种。 思路
DFS是一种,我们首先计算出完整的路径我们一共要走的步数,以及起始点和终点的坐标。然后我们有以下终止条件:
动态规划也是一种思路。 整体来说动态规划的思路和DFS比较相似。在leetcode上两者的耗时也基本一致。如下图所示。 代码:
class Solution {
public:
bool isVaild ( int x, int y, int m, int n) {
if ( x>= 0 && x< m && y>= 0 && y< n) {
return true;
}
return false;
}
int dxs[ 4 ] = { 1 , 0 , - 1 , 0 } ;
int dys[ 4 ] = { 0 , 1 , 0 , - 1 } ;
void uniquePathsIIIRecursive ( const vector< vector< int >> & grid, int m, int n, int x, int y, int step,
int total_step, bool* visits, int & res) {
if ( step == total_step) {
if ( grid[ x] [ y] == 2 )
res + = 1 ;
return ;
}
if ( grid[ x] [ y] == 2 ) {
return ;
}
for ( int dir_id= 0 ; dir_id< 4 ; dir_id++ ) {
int new_x = x + dxs[ dir_id] ;
int new_y = y + dys[ dir_id] ;
if ( isVaild ( new_x, new_y, m, n) ) {
int visit_pos = new_x * n + new_y;
if ( ! visits[ visit_pos] && grid[ new_x] [ new_y] != - 1 ) {
visits[ visit_pos] = true;
uniquePathsIIIRecursive ( grid, m, n, new_x, new_y, step + 1 , total_step, visits, res) ;
visits[ visit_pos] = false;
}
}
}
}
int uniquePathsIII ( vector< vector< int >> & grid) {
int m = ( int ) grid. size ( ) ;
if ( m == 0 ) {
return 0 ;
}
int n = ( int ) grid[ 0 ] . size ( ) ;
bool visits[ m * n] ;
memset ( visits, false, sizeof ( visits) ) ;
int total_step = 0 ;
int start_x = 0 ;
int start_y = 0 ;
for ( int i= 0 ; i< m; i++ ) {
for ( int j= 0 ; j< n; j++ ) {
if ( grid[ i] [ j] == 0 || grid[ i] [ j] == 2 ) {
total_step + = 1 ;
}
if ( grid[ i] [ j] == 1 ) {
start_x = i;
start_y = j;
}
}
}
int res = 0 ;
visits[ start_x * n + start_y] = true;
uniquePathsIIIRecursive ( grid, m, n, start_x, start_y, 0 , total_step, visits, res) ;
return res;
}
int code ( int x, int y, int m, int n) {
return 1 << ( x * n + y) ;
}
int uniquePathsIII_V2 ( vector< vector< int >> & grid) {
int m = ( int ) grid. size ( ) ;
if ( m == 0 ) {
return 0 ;
}
int n = ( int ) grid[ 0 ] . size ( ) ;
int start_x;
int start_y;
int target_x;
int target_y;
int target = 0 ;
for ( int i= 0 ; i< m; i++ ) {
for ( int j = 0 ; j < n; j++ ) {
if ( grid[ i] [ j] == 0 ) {
target | = code ( i, j, m, n) ;
} else {
if ( grid[ i] [ j] == 1 ) {
start_x = i;
start_y = j;
} else {
if ( grid[ i] [ j] == 2 ) {
target | = code ( i, j, m, n) ;
target_x = i;
target_y = j;
}
}
}
}
}
return dp ( start_x, start_y, m, n, target_x, target_y, target) ;
}
int dp ( int x, int y, int m, int n, int target_x, int target_y, int to_do) {
if ( to_do == 0 ) {
if ( x == target_x && y == target_y)
return 1 ;
return 0 ;
}
if ( x == target_x && y == target_y)
return 0 ;
int ans = 0 ;
for ( int i= 0 ; i< 4 ; i++ ) {
int new_x = x + dxs[ i] ;
int new_y = y + dys[ i] ;
if ( isVaild ( new_x, new_y, m, n) ) {
if ( to_do & code ( new_x, new_y, m, n) )
ans + = dp ( new_x, new_y, m, n, target_x, target_y, to_do ^ code ( new_x, new_y, m, n) ) ;
}
}
return ans;
}
} ;