经典排列组合与动态规划题
[size=medium][b]一、原题:[/b][/size]
[size=medium][b]解法一[/b][/size]
[size=medium][b]解法二[/b][/size]
[size=medium][b]解法三[/b][/size]
[size=medium][b]解法四[/b][/size]
[size=medium][b]二、增加些难度[/b][/size]
-
[size=medium][b]一、原题:[/b][/size]
// https://leetcode.com/problems/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?
+---+---+---+---+---+---+---+---+
|ROB| | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | | | |end|
+---+---+---+---+---+---+---+---+
*/
[size=medium][b]解法一[/b][/size]
/*
// https://discuss.leetcode.com/topic/5623
// java-dp-solution-with-complexity-o-n-m
The assumptions are:
- When (n==0||m==0) the function always returns 1 since the robot
can't go left or up.
- For all other cells. The result = uniquePaths(m-1,n) + uniquePaths(m,n-1)
Therefore I populated the edges with 1 first and use DP to get the full 2-D array.
*/
/*
+----+----+----+----+----+----+----+----+
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+----+----+----+----+----+----+----+----+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+----+----+----+----+----+----+----+----+
| 1 | 3 | 6 | 10 | 15 | 21 | 28 | 36 |
+----+----+----+----+----+----+----+----+
| 1 | 4 | 10 | 20 | 35 | 56 | 84 |120 |
+----+----+----+----+----+----+----+----+
*/
// Time complexity: O(n^2)
public int uniquePaths(int m, int n) {
int[][] map = new int[m][n];
for(int i = 0; i < m; i++){
map[i][0] = 1;
}
for(int j = 0; j < n; j++){
map[0][j] = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
map[i][j] = map[i-1][j] + map[i][j-1];
}
}
return map[m-1][n-1]; // the finish star.
}
[size=medium][b]解法二[/b][/size]
// Time complexity: O(n^2)
public int uniquePaths(int m, int n) {
int[]dp = new int[n];
dp[0] = 1;
for(int i = 0; i < m; i++)
for(int j = 1; j < n; j++)
dp[j] = dp[j] + dp[j-1];
return dp[n-1]; // the finish star.
}
[size=medium][b]解法三[/b][/size]
// Time complexity: O(n)
/*
https://discuss.leetcode.com/topic/52660
// java-0ms-solution-with-explanations
When we solve this problem, we should keep in mind that this is a
permutation and combination problem of high school level.
Therefore, we need not to use DP solution or recursive solution.
Given m and n, there will be m+n-2 steps.
Among these m+n-2 steps, n-1 steps are towards right and m-1 steps are towards down.
the question is changed to: Select m-1 steps from m+n-2 steps.
So, there will be (m-1)C(m+n-2) solutions, which is the same as (n-1)C(m+n-2).
All we need is to write a program quickly calculating (m-1)C(m+n-2) or (n-1)C(m+n-2).
*/
public int uniquePaths(int m, int n) {
long result = 1;
int steps = m + n - 2;
for(int i=0; i < Math.min(m-1,n-1); i++)
result = result * (steps - i) / (i + 1);
return (int)result;
}
/*
注意:
result = result * (steps - i) / (i + 1);
不要写成
result *= (steps - i) / (i + 1);
的形式,否则后者在做除法时丢位导致结果错误。
*/
[size=medium][b]解法四[/b][/size]
// Time complexity: O(n)
/*
https://discuss.leetcode.com/topic/52660
// java-0ms-solution-with-explanations
https://discuss.leetcode.com/topic/31724
// java-solution-0ms-4lines
When we solve this problem, we should keep in mind that this is a
permutation and combination problem of high school level.
Therefore, we need not to use DP solution or recursive solution.
Given m and n, there will be m+n-2 steps.
Among these m+n-2 steps, n-1 steps are towards right and m-1 steps are towards down.
the question is converted to: Select m-1 steps from m+n-2 steps.
So, there will be (m-1)C(m+n-2) solutions, which is the same as (n-1)C(m+n-2).
All we need is to write a program quickly calculating (m-1)C(m+n-2) or (n-1)C(m+n-2).
*/
/*
基础知识:(从 n 个数中 取出 m 个数)
排列公式: result = n!/(n-m)!
组合公式: result = n!/(n-m)!/m!
------------------------------------------------------
该题是一个组合题:
7, 3
steps = 8
n = 3
result = 8!/(3!*(8-3)!)
8 7 6 5 4 3 2
- - - * - - - -
3 2 1 5 4 3 2
*/
public int uniquePaths(int m, int n) {
int steps = m + n - 2;
int min = Math.min(m - 1, n - 1);
long sum = 1, sub = 1;
for(int i = 0; i < min; i++){
sum *= (steps - i);
sub *= (min - i);
}
return (int)(sum/sub);
}
/*
注意:这种解法乘完再除,相乘的结果可能会造成溢位,而出错。
所以只适合数比较小的情况。
*/
[size=medium][b]二、增加些难度[/b][/size]
/*
https://leetcode.com/problems/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.
*/
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int width = obstacleGrid[0].length;
int[] dp = new int[width];
dp[0] = 1;
for (int[] row : obstacleGrid) {
for (int j = 0; j < width; j++) {
if (row[j] == 1)
dp[j] = 0;
else if (j > 0)
dp[j] += dp[j - 1];
}
}
return dp[width - 1];
}
-