Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
nooblong committed Aug 28, 2024
1 parent 5b5c422 commit 4e71f2f
Show file tree
Hide file tree
Showing 17 changed files with 16 additions and 16 deletions.
32 changes: 16 additions & 16 deletions _posts/2024-03-04-好文.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ img_path: /assets/
- 动态规划的解题套路
- leetcode案例分析

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/01fdad6c74864d7da07193203c2dcbf4~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/a.png)

公众号:**捡田螺的小男孩**

Expand All @@ -36,7 +36,7 @@ img_path: /assets/

动态规划最核心的思想,就在于**拆分子问题,记住过往,减少重复计算**

![动态规划在于记住过往](img/2024-03-04-%E5%A5%BD%E6%96%87/d26f967ff6e447d291b0b196c4edaa07~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![动态规划在于记住过往](img/2024-03-04-%E5%A5%BD%E6%96%87/b.png)

我们来看下,网上比较流行的一个例子:

Expand Down Expand Up @@ -99,11 +99,11 @@ scss

去leetcode提交一下,发现有问题,超出时间限制了

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/3e0608ec89a246568e01c7ba4b8f50d8~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/c.png)

为什么超时了呢?递归耗时在哪里呢?先画出**递归树**看看:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/2dd95840552e4a7db9536884b7a9b558~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/d.png)

- 要计算原问题 f(10),就需要先计算出子问题 f(9) 和 f(8)
- 然后要计算 f(9),又要先算出子问题 f(8) 和 f(7),以此类推。
Expand All @@ -130,19 +130,19 @@ scss

- 第一步,f(10)= f(9) + f(8),f(9) 和f(8)都需要计算出来,然后再加到备忘录中,如下:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/94484290462e45c799609b0a581b14b0~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/e.png)

- 第二步, f(9) = f(8)+ f(7),f(8)= f(7)+ f(6), 因为 f(8) 已经在备忘录中啦,所以可以省掉,f(7),f(6)都需要计算出来,加到备忘录中~

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/12900b17d77f4adfbdb71920f729d61a~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/a1.png)

第三步, f(8) = f(7)+ f(6),发现f(8),f(7),f(6)全部都在备忘录上了,所以都可以剪掉。

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/9a8c7ba6b5ae413799c6a33490bb1f8f~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/b1.png)

所以呢,用了备忘录递归算法,递归树变成光秃秃的树干咯,如下:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/18a78d6b99a84ff8a1df834f3c085014~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/c1.png)

**备忘录**的递归算法,子问题个数=树节点数=n,解决一个子问题还是O(1),所以带**备忘录**的递归算法的时间复杂度是O(n)。接下来呢,我们用带**备忘录**的递归算法去撸代码,解决这个青蛙跳阶问题的超时问题咯~,代码如下:

Expand Down Expand Up @@ -174,7 +174,7 @@ kotlin

去leetcode提交一下,如图,稳了:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/e5f0fb1998c542dc8cb3826de800f443~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/d1.png)

其实,还可以用动态规划解决这道题。

Expand All @@ -194,11 +194,11 @@ kotlin

我们来看下自底向上的解法,从f(1)往f(10)方向,想想是不是直接一个for循环就可以解决啦,如下:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/8e21b14d47e64afa958506d49972827b~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/e1.png)

带备忘录的递归解法,空间复杂度是O(n),但是呢,仔细观察上图,可以发现,f(n)只依赖前面两个数,所以只需要两个变量a和b来存储,就可以满足需求了,因此空间复杂度是O(1)就可以啦

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/8b202b2364eb4aae9122cfa8474c045e~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/f1.png)

动态规划实现代码如下:

Expand Down Expand Up @@ -250,7 +250,7 @@ ini
- 当台阶是4级时,想跳到第3级台阶,要么是先跳到第3级,然后再跳1级台阶上去,要么是先跳到第 2级,然后一次迈 2 级台阶上去。所以f(4) = f(3) + f(2) =5
- 当台阶是5级时......

![自底向上的动态规划](img/2024-03-04-%E5%A5%BD%E6%96%87/29cd6d0d31514336baf9905f8084a624~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![自底向上的动态规划](img/2024-03-04-%E5%A5%BD%E6%96%87/g1.png)

#### 2. 确定边界

Expand All @@ -266,7 +266,7 @@ n>=3时,已经呈现出规律 f(n) = f(n-1) + f(n-2) ,因此,f(n-1)和f(n-

通过前面3步,穷举分析,确定边界,最优子结构,我们就可以得出状态转移方程啦:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/4fb4cd7257ff4fcbac9d87be96f353bd~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/a2.png)

#### 5. 代码实现

Expand Down Expand Up @@ -346,11 +346,11 @@ css

是不是感觉成功了一半呢?但是**如何把nums[i]结尾的递增子序列也转化为对应的子问题**呢?要是nums[i]结尾的递增子序列也跟nums[i-1]的最长递增子序列有关就好了。又或者nums[i]结尾的最长递增子序列,跟前面子问题num[j](0=<j<i)结尾的最长递增子序列有关就好了,带着这个想法,我们又回头看看穷举的过程:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/41d5ff02fc4b4da9bb6de5d3a1ba7c25~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/b2.png)

nums[i]的最长递增子序列,不就是**从以数组num[i]每个元素结尾的最长子序列集合,取元素最多(也就是长度最长)那个嘛**,所以原问题,我们转化成求出以数组nums每个元素结尾的最长子序列集合,再取**最大值**嘛。哈哈,想到这,我们就可以**用dp[i]表示以num[i]这个数结尾的最长递增子序列的长度**啦,然后再来看看其中的规律:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/79287ac2dd7d47f9beb811d0c3630409~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/c2.png)

其实,**nums[i]结尾的自增子序列,只要找到比nums[i]小的子序列,加上nums[i]** 就可以啦。显然,可能形成多种新的子序列,我们选最长那个,就是dp[i]的值啦

Expand Down Expand Up @@ -381,7 +381,7 @@ scss

通过前面分析,我们就可以得出状态转移方程啦:

![img](img/2024-03-04-%E5%A5%BD%E6%96%87/457ce281c1ec4e91b8c868aa593e41b6~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp)
![img](img/2024-03-04-%E5%A5%BD%E6%96%87/d2.png)

所以数组num[i]的最长递增子序列就是:

Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes

0 comments on commit 4e71f2f

Please sign in to comment.