一. Unique Paths
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?
Above is a 3 x 7 grid. How many possible unique paths are there?
Note: m and n will be at most 100.
Difficulty:Medium
TIME:12MIN
解法一(動態規劃)
這道題,按題目說的數據量,如果採用搜索來做,超時肯定超到天邊去了。
這道題可以用動態規劃來求解:
- 如果只有一行,那麼當然只有一條路可以走,那麼可以設定一個數組爲[1,1,1,1,1,1,1],表示從該點到終點的所有可能路徑數。
- 如果有兩行,我們會發現,第一行的路徑數變爲了[7,6,5,4,3,2,1],爲下面那一行所有可能路徑數的疊加值。
- 同理,如果有三行,那麼第一行的路徑就是第二行路徑的疊加值,而第二行路徑爲最後一行路徑的疊加值。
因此,代碼如下:
int uniquePaths(int m, int n) {
vector<int> v(n,1);
while(m > 1) {
for(int i = 1; i < n; i++)
v[i] += v[i - 1];
m--;
}
return v[n - 1];
}
代碼的時間複雜度爲
解法二(公式求解)
既然每次向右走和每次向下走的選擇都會創造一條獨一無二的路徑,那麼我們可以把行走的路徑看出一個排列
比如其中一條路徑就可以表示爲[D,D,R,R,R,R,R,R],就是一直往下走,到底後就一直往右走。而且,任意兩個D和六個R的排列,都是一條獨一無二的路徑,所以,我們只要求出了兩個D和六個R的所有排列數,就相當於求解了3 x 7 grid的所有路徑數。
求全排列總數的公式爲
int uniquePaths(int m, int n) {
int big = max(m - 1, n - 1);
int small = min(m - 1, n - 1);
long result = 1;
for(int i = 1, j = big + 1; i <= small; i++, j++) {
result *= j;
result /= i;
}
return (int)result;
}
代碼的時間複雜度爲
二. Unique Paths II
Follow up for “Unique Paths”:
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as 1 and 0 respectively in the grid.
For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below.
[
[0,0,0],
[0,1,0],
[0,0,0]
]
The total number of unique paths is 2.
Note: m and n will be at most 100.
Difficulty:Medium
TIME:16MIN
解法(動態規劃)
題目改變之後應該是不能用公式來直接求解了,不過還是可以用動態規劃來求解。
上面說過是求疊加值,那是因爲第一題是第二題的一種特例,其實這道題的最優子結構具體來說可以描述爲:
- dp[i][j] = dp[i+1][j]+dp[i][j+1];
也就是往右邊走以及往下走的所有路徑之和,而且如果該點爲障礙,那麼就直接把值設爲0即可。
其實這道題自己創建個數組可能會比較簡單(就是創建m+1行n+1列的數組),這樣處理的邊界情況會少很多,不過爲了節省空間,我還是使用了輸入的數組作爲動態規劃的數組。
int uniquePathsWithObstacles(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
/*初始化最後一行*/
grid[m - 1][n - 1] = 1 - grid[m - 1][n - 1];
for(int i = n - 2; i >= 0; i--) {
grid[m - 1][i] = grid[m - 1][i] != 1 ? grid[m - 1][i + 1] : 0;
}
for(int i = m - 2; i >= 0; i--) {
/*初始化該行最後一個點*/
grid[i][n - 1] = grid[i][n - 1] != 1 ? grid[i + 1][n - 1] : 0;
for(int j = n - 2; j >= 0; j--) {
//dp過程
grid[i][j] = grid[i][j] != 1 ? (grid[i][j + 1] + grid[i + 1][j]) : 0;
}
}
return grid[0][0];
}
代碼的時間複雜度爲