diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md index 8e82007e..86c42150 100644 --- a/problems/0063.不同路径II.md +++ b/problems/0063.不同路径II.md @@ -155,6 +155,39 @@ public: * 时间复杂度:$O(n × m)$,n、m 分别为obstacleGrid 长度和宽度 * 空间复杂度:$O(n × m)$ + +同样我们给出空间优化版本: +```CPP +class Solution { +public: + int uniquePathsWithObstacles(vector>& obstacleGrid) { + if (obstacleGrid[0][0] == 1) + return 0; + vector dp(obstacleGrid[0].size()); + for (int j = 0; j < dp.size(); ++j) + if (obstacleGrid[0][j] == 1) + dp[j] = 0; + else if (j == 0) + dp[j] = 1; + else + dp[j] = dp[j-1]; + + for (int i = 1; i < obstacleGrid.size(); ++i) + for (int j = 0; j < dp.size(); ++j){ + if (obstacleGrid[i][j] == 1) + dp[j] = 0; + else if (j != 0) + dp[j] = dp[j] + dp[j-1]; + } + return dp.back(); + } +}; +``` + +* 时间复杂度:$O(n × m)$,n、m 分别为obstacleGrid 长度和宽度 +* 空间复杂度:$O(m)$ + + ## 总结 本题是[62.不同路径](https://programmercarl.com/0062.不同路径.html)的障碍版,整体思路大体一致。 diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md index ca5fba77..69a6d0d6 100644 --- a/problems/0236.二叉树的最近公共祖先.md +++ b/problems/0236.二叉树的最近公共祖先.md @@ -45,9 +45,13 @@ 接下来就看如何判断一个节点是节点q和节点p的公共公共祖先呢。 -**如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。** +**首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。** -使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现如何这个条件的节点,就是最近公共节点了。 +**但是很多人容易忽略一个情况,就是节点本身p(q),它拥有一个子孙节点q(p)。** + +使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现满足第一种情况的节点,就是最近公共节点了。 + +**但是如果p或者q本身就是最近公共祖先呢?其实只需要找到一个节点是p或者q的时候,直接返回当前节点,无需继续递归子树。如果接下来的遍历中找到了后继节点满足第一种情况则修改返回值为后继节点,否则,继续返回已找到的节点即可。为什么满足第一种情况的节点一定是p或q的后继节点呢?大家可以仔细思考一下。** 递归三部曲: