菜鸡每日一题系列打卡62天
每天一道算法题目
小伙伴们一起留言打卡
坚持就是胜利,我们一起努力!
题目描述(引自LeetCode)
一个机器人位于一个m x n网格的左上角(起始点在下图中标记为“Start”)。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。问总共有多少条不同的路径?
例如,上图是一个7 x 3的网格。有多少可能的路径?
示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
提示:
1 <= m, n <= 100
题目数据保证答案小于等于2 * 10 ^ 9
题目分析
这道题如果不是放在leecode上,那妥妥的是一道排列组合数学题。但是作为一道算法题目而言,排列组合的思路固然是对的,但是实现上容易导致溢出(对Java而言),因此,在此仅说一下排列组合的思路,不作具体的实现。在一个m x n的网格上,要想从起点到达终点,必然会向右走m - 1步,向下走n - 1步,也即一共走m + n - 2步,只需从中选出m - 1步向右走,其余的向下走即可,(也可从中选出n - 1步向下走,其余的向右走,结果是一样的),因此,答案便是
就本题而言,菜鸡认为动态规划的解法比较合适。而动态规划最关键的就是找状态转移方程。
比较容易想到的是采用一个二维数组去进行模拟,dp[i][j] = dp[i - 1][j] + dp[i][j - 1]。
但事实上,我们仅仅需要当前行与上一行的数据,因此,使用二维数组是一种空间的浪费,我们可以对其进行优化,采用两个一维数组进行状态存储,dp[j] = tmp[j] + dp[j - 1],其中tmp[j]表示上一行的状态。
更进一步考虑,实际上tmp[j]可以用赋值之前的dp[j]代替,也即dp[j] = dp[j] + dp[j - 1]。
本题的动态规划的优化是有技巧性可言的,小伙伴们可以通过上述步骤进行思考总结,而菜鸡将在代码实现过程中,对空间复杂度进行进一步优化!话不多说,上代码!
代码实现
class Solution {
public int uniquePaths(int m, int n) {
// 预处理
if (m > n) {
int tmp = m;
m = n;
n = tmp;
}
// 申请动态规划数组并初始化
int[] result = new int[m];
Arrays.fill(result, 1);
// 计算结果
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
result[j] += result[j - 1];
}
}
// 返回结果
return result[m - 1];
}
}
代码分析
对代码进行分析,时间复杂度为O(mn),空间复杂度在经过预处理之后,下降到了O(min(m, n))。
执行结果
学习 | 工作 | 分享
????长按关注“有理想的菜鸡”
只有你想不到,没有你学不到