算法学习——动态规划

引言

前几天,做一道关于,最长不重复字符串的leetcode的题,做完之后对于题目的速度不很满意,所以上网找了相关资料。找到了一种算法,作者自己说是用到了动态规划的算法。我也就顺便把动态规划相关的知识顺便给总结一下 。

一.什么是动态规划

关于什么是动态规划,引用和总结《算法导论》这本书里面说的,相对于分治法动态规划适用于子问题不是独立的情况,也就是说问题本身包含公共子问题的情况。如果用分治法我们就会做许多不必要的工作。而用动态规划,我们就可以将子问题的结果保存起来(注意,个人认为这里是关键所在)等到需要用的时候再用。
值得注意的是,动态规划主要是用在**最优化问题**上面的,如果一个问题有多个最优解,动态规划是求其中一个最优解。
上面的介绍如果,你不是很懂没关系。接下来我们将用几个例子来逐步加深理解。

二.动态规划实例

在讲解动态规划例子之前,我们需要知道,动态规划求解过程中可以分为以下四个步骤:
①描述最优结构
②递归定义最优解的值
③按自底向上的方式计算最优的值。
④由计算的结果构造出一个最优解。
其中第1-3是动态规划的基础。

1.最长不重复子串问题。

首先,我们来看看这个问题:
*Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.*
题目很简单,求一个字符串中,最长的不重复子串,那么我们要怎么用动态规划来解决这个问题呢?

①描述最优结构

首先,我们要明白,最长的子串肯定是被两个相同的字符夹在中间的子串在加上字符本身组成的(abca,就是bc+a),当然还有一种情况就是,字符串本身,没有重复字符。所以要找最长子串就是,找到,两个最近字符间最远距离。
我们假设存在最长的字符串,且是以s[j]为结尾,其长度为l[j],那么要求出最长的子串,只要分别求出max(l[0..n-1])就好。现在我们求s[k]结尾的最长字符串,那么以s[k-1]结尾的最长字符串,必然是存在的,设为s[i..k-1]。
现在以s[k]为结尾的最长子串只有以下两个:
①s[i..k-1],中不存在s[g]==s[k],那么显然l[k]=l[k-1]+1。
②s[i..k-1],中存在s[g]==s[k],那么l[k]=k-g。

②递归定义最优值

因此可以得到
l(n)=1l(k1),kg,n==0s[g]==s[k]

③计算最优的值。

以“abcabcaa”为例子构造出下表(便于理解,实际编程中可以用数组存储)

下标 il[i]
01
12
23
33
43
53
63
71

④构建最优解

从表格我们就可以求出最优解得长度为3。
到这里,我们的问题的就基本解决了,不难看出我们,只要把第一步骤完成,后面的问题其实也就不难解决。
注意:在这个问题中,我们有个小技巧要注意,我们可以用一个数组记录,记录每个字符最近出现过的下标是多少,回头遍历子串中是否 存在s[g]==s[k]。这样,我们就可以把算法的复杂度控制在O(N)了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值