leetcode 力扣 62.不同路径(动态规划经典例题)

本文探讨了一道经典的动态规划问题——机器人如何从网格左上角到达右下角,通过分析超时的暴力递归解法,引入了动态规划的优化解决方案。作者展示了如何使用二维数组和一维数组实现动态规划,并给出了进一步的空间复杂度优化。此外,还提到了使用排列组合公式作为替代解法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

在这里插入图片描述

解题思路:

首先我们尝试着用暴力递归去解题,但是毫无疑问出现了超时无法提交成功,所以我们可以尝试一下dp
这是动态规划的一道经典例题,我们首先定义一个二维数组p[][]来表示到每个位置的路径条数,由题设我们可以看出,对于任意位置(x,y),只能由(x,y-1)向下走一步或者由位置(x-1,y)向右走一步到达,所以可以得到递推关系p[x][y]=p[x-1][y]+p[x][y-1],我们可以让p[0][0]=1,而p[m-1][n-1]就是我们要求的结果,这样做出来的时间复杂度和空间复杂度都是O(mn)

注意事项:

还有要注意的是,由于机器人只能向右或者向下,所以我们可以让p[0][i]和p[i][0]的值直接为1


代码:

int uniquePaths(int m, int n) {
    int i,j;
	int p[m][n];
    for(i=0;i<m;++i) 
	{
        p[i][0]=1;
    }
    for (j=0;j<n;++j) 
	{
        p[0][j]=1;
	}	
    for(i=1;i<m;++i) 
	{
        for(j=1;j<n;++j) 
		{
            p[i][j]=p[i-1][j]+p[i][j-1];
        }
    }
    return p[m-1][n-1];
}

运行结果:

在这里插入图片描述

运行结果
(力扣的运行时间大家都清楚,做一个参考就好)

解法优化:

思路:

在创建二维数组的时候会占用较大的空间,所以我们可以尝试一下将二维数组压缩成一维数组进行dp,这样空间复杂度可以降为O(n)

原理;

在每次循环中p[j]是上一次循环时j位置数组的元素值,而p[j-1]的值是左边的值,相当于把二维数组压缩为一维数组

代码:

int uniquePaths(int m, int n) {
    int i,j;
	int p[n];
    p[0] = 1;
    if(m>n)
    {
    	int t;
    	t=m;
    	m=n;
    	n=t;
    }	//交换m,n
    for(i=1;i<n;i++)
    {
    	p[i]=0;
	}
	for(i=0;i<m;i++) 
	{
        for(j=1;j<n;j++) 
		{
            p[j]+=p[j-1];
        }
    }
    return p[n-1];
}

运行结果:

在这里插入图片描述


其他解法:

同样,我们也可以用到高中数学的排列组合方法来解这道题,由于机器人一共会走m+n-2步,那么直接m+n-2中挑出m-1步向下走即可,那么最终结果就是C(m-1)(m+n-2)

代码:

int uniquePaths(int m, int n) {
    long long int path = 1;
    for (int x = n, y = 1; y < m; ++x, ++y) {
        path = path * x / y;
    }
    return path;
}

运行结果: 在这里插入图片描述


知识点:

动态规划:动态规划常是用来求最优解的一种途径,在求全局最优解的过程中,分治思想是较为常见的一种解题途径,但如果子问题之间不独立,则适合用动态规划思想。而动态规划和贪心算法的不同之处是,动态规划是针对全局求最优解,而贪心算法是针对上一个最优解继续求最优解0。同时,由于在动态规划的过程中要存储各种状态,所以会占用更多空间,是一种以空间换时间的方法。在动态规划中,核心的步骤是找到数组元素之间的关系式

### 力扣上的并查集示例题目 #### 题目概述 在 LeetCode 上,并查集是一种非常常见的算法设计模式,用于解决涉及连通性和分组的问题。以下是几个经典的并查集相关题目及其描述。 --- #### 经典题目解析 1. **岛屿数量 (Number of Islands)** 这是一个经典问题,目标是在二维网格中计算由 '1' 表示的陆地组成的岛屿的数量[^2]。可以使用 DFS、BFS 或者并查集来实现。如果选择并查集方法,则可以通过 `union` 操作将相邻的陆地标记为同一集合,最终统计独立集合的数量得到答案。 2. **最长连续序列 (Longest Consecutive Sequence)** 输入一个未排序的整数数组,找到其中最长的连续子序列长度[^3]。此问题可以用哈希表或者并查集求解。通过构建节点之间的连接关系,利用并查集中的 `find` 和 `union` 方法动态维护最大连通区域大小。 3. **朋友圈 (Friend Circles)** 描述了一群学生之间是否存在友谊关系的情况,判断总共有多少个互不相交的朋友圈[^1]。这道题可以直接映射到标准的并查集模型上——每一对朋友视为一条边,执行相应的合并操作后查询总的连通分支数目即可得出结果。 4. **账户合并 (Accounts Merge)** 提供多个电子邮件地址列表以及它们所属用户的姓名信息,要求按照实际拥有这些邮箱的人重新整理输出形式[^4]。这里同样适用基于字符串键值建立图结构再借助并查集完成归类处理逻辑。 5. **冗余连接 II (Redundant Connection II)** 假设树形拓扑被破坏成含有环路的状态,请找出造成这种情况的一条多余边并移除恢复原状。运用带权版并查集技巧检测何时形成闭环从而定位错误链接位置。 --- ```python class UnionFind: def __init__(self, n): self.parent = list(range(n)) def find(self, p): while p != self.parent[p]: self.parent[p] = self.parent[self.parent[p]] # 路径压缩 p = self.parent[p] return p def union(self, p, q): rootP = self.find(p) rootQ = self.find(q) if rootP == rootQ: return False self.parent[rootP] = rootQ return True ``` 上述代码片段展示了如何定义一个基础版本的支持按秩合并与路径压缩优化后的并查集数据结构实例化过程。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值