题目:给定一个由参数m,n表示行数和列数而形成的2维表格,以左上为出发点,右下为目的地,每次只能向右走一步,或者向下走一步,算出总共存在多少不同的到达路径。
分析;这个问题的递归属性是很明显的,因为无论向右走还是向下走,到达一个新的位置,这时就变成了在该新位置到达目的地有多少不同的路径。其次,向右走和向下走是不同的路径,最终的结果应该是二者的和。
递归的返回条件:n = 1 或 m = 1, 对于这种没选择的单方向,只能是返回1。
int uniquePaths_recursion(int m, int n) { if( 1 == n || 1 == m) return 1; return uniquePaths_recursion(m - 1, n) + uniquePaths_recursion(m, n - 1); }
当解题思路正确,且递归可以实现,只是时间超时的时候,就是该考虑dp的时候了,dp与递归明显的优势就是会记录子问题的状态,不用重复的计算子问题。这就节省了很多的时间。
dp[ i, j ] :表示从出发点到达(i,j)点不同的路径数。
状态转移方程:dp[ i, j ] = dp[ i - 1, j] + dp[ i, j - 1]。其意义是,到达(i,j) 可以是通过上一位置向右移动或上一位置向下移动完成的。
初始条件:dp[ i, 0] = 1, dp[ 0, j ] = 1。因为在第一行的所有位置,只能是上一位置向右走完成的,同理,第一列的所有位置只能是上一位置向下移动完成的,这里将出发点也设置为1了,没关系,我们不会用到出发点的信息。
返回值:dp[m,n]。
通过观察状态转移方程,当前的位置只跟上一位置有关,跟上上一次的位置都是无关的,而上一位置只能是在其上面或在其左面,所以我们可以定义两个变量,而无需定义m*n的表。
int uniquePaths_dp(int m, int n){ if(1 == n || 1 == n) return 1; //initial vector<int> pre_dp( n, 1); for (int i = 1; i < m; ++i) { vector<int> cur_dp(n, 1); for (int j = 1; j < n; ++j) { cur_dp[j] = cur_dp[j - 1] + pre_dp[j]; } pre_dp = cur_dp; } return pre_dp[n - 1]; }
原文:http://blog.csdn.net/shiquxinkong/article/details/26709041