动态规划--最长公共子数组

题目链接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/

     给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。

     示例:

     输入:

     A: [1,2,3,2,1]

     B: [3,2,1,4,7]

     输出:3

     解释:

     长度最长的公共子数组是 [3, 2, 1] 。

     提示:

     1 <= len(A), len(B) <= 1000

     0 <= A[i], B[i] < 100

思路:

动态性的问题,最适合动态规划来解决;

//定义二维数组,表示数组A的第i位与数组B的第j位是否相等的状态,0代表不相等,1代表相等 (此处二维数组的长度为长度+1,这样定义对于极值处理有益)

var dp : [[Int]] = [[Int]](repeating: [Int](repeating:0, count: bSize+1), count: aSize+1)

动态规划三部曲:

 step1:推导公式

    以A数组为横坐标,B数组为纵坐标定义二维数组

二维数组图(绿色框内为二维数组)

通过二维数组图可以,dp[i][j]只能由dp[i-1][i-1]共同决定了最长公共子数组的长度是否可继续+1(红色部分)

         if A[i]==B[j] 可知: dp[i][j]=dp[i-1][j-1]+1

step2:初始化

         根据dp[i][j] 可知 dp[i][0] dp[0][j]的值没有多大意义,重要的是dp[i-1][j-1]

         所以默认全部初始化为0即可


step3:写循环体

         注意:循环体从1开始,是为了处理i-1与j-1极值的问题


         时间复杂度:O(i*j)

         空间复杂度:O(i*j)

func findLength(_ A:[Int], _ B:[Int]) -> Int{

        let aSize = A.count

        let bSize = B.count

        var dp : [[Int]] = [[Int]](repeating: [Int](repeating:0, count: bSize+1), count: aSize+1)

        var result : Int=0

        for i in 1 ... aSize {

            for j in 1 ... bSize {

                if A[i-1] == B[j-1] {//此处与上面分析推导公式不一致,是因为从1开始,而非从0

                    dp[i][j] = dp[i-1][j-1]+1

                }

                result =max(dp[i][j], result)

            }

        }

        return result

    }

题目链接:

     https://leetcode-cn.com/problems/longest-common-subsequence/

     最长公共子序列

     给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。

     一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

     例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

     若这两个字符串没有公共子序列,则返回 0。


     示例 1:

     输入:text1 = "abcde", text2 = "ace"

     输出:3

     解释:最长公共子序列是 "ace",它的长度为 3。

     示例 2:

     输入:text1 = "abc", text2 = "abc"

     输出:3

     解释:最长公共子序列是 "abc",它的长度为 3。

     示例 3:

     输入:text1 = "abc", text2 = "def"

     输出:0

     解释:两个字符串没有公共子序列,返回 0。


     提示:

     1 <= text1.length <= 1000

     1 <= text2.length <= 1000

     输入的字符串只含有小写英文字符。

思路:

定义dp数组,二维数组,横坐标为test1,纵坐标为test2

     var dp:[[Int]] = [[Int]](repeating: [Int](repeating: 0, count: aSize+1), count: bSize+1)

     注意:此处动态二维数组长度为aSize+1,bSize+1;是因为从1开始存储数据,0位默认位0,方便后续比较前一位内容,否则还需要判断下标越界

dp数组

动态规划三部曲:

step1:确定推导公式

通过上图可知:

dp[i][j]对应的状态值由test1[i-1] 与test2[j-1]的值决定

如果test1[i-1] = test2[j-1],那么dp[i][j] = dp[i-1][j-1] + 1

如果test1[i-1] != test2[j-1],那么dp[i][j] = max(dp[i-1][j],dp[i][j-1])

所以推导公式为:

if test1[i-1] == test2[j-1]  {

    dp[i][j] = dp[i-1][j-1] + 1

}else{

    dp[i][j] = max(dp[i-1][j],dp[i][j-1])

}

step2:初始化

初始化的时候不能确定二者是否有相等的字符,所以初始赋值全部为0

step3:写循环体

代码如下:

func longestCommonSubsequence(_ test1:String, _ test2: String) -> Int{

        let aSize : Int= test1.count

        let bSize : Int= test2.count

        let test1List: [Character] = Array(test1)

        let test2List: [Character] = Array(test2)

        var dp:[[Int]] = [[Int]](repeating: [Int](repeating:0, count: aSize+1), count: bSize+1)

        for i in 1 ... bSize {

            for j in 1 ...  aSize {

                if test2List[i-1]  ==  test1List[j-1] {

                    dp[i][j] = dp[i-1][j-1] +1

                }else{

                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])

                }

            }

        }

        return dp[bSize][aSize]

    }

题目链接:https://leetcode-cn.com/problems/is-subsequence/

     给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

     字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

     示例 1:

     输入:s = "abc", t = "ahbgdc"

     输出:true


     示例 2:

     输入:s = "axc", t = "ahbgdc"

     输出:false


     提示:

     0 <= s.length <= 100

     0 <= t.length <= 10^4

     两个字符串都只由小写字符组成。

思路:使用动态规划(此题与上一题类似,具体图参考上一题的图)

动态规划三部曲

         1、确定推导公式(由图可知)

         if tArray[j-1] == sArray[i-1]  dp[i][j] = dp[i-1]+1

         else dp[i][j] = max(dp[i-1][j],dp[i][j-1])

         需要注意的是,字符比较的时候,需要先-1,因为数组是从索引为1的位置开始,默认第一位全部补0,便于循环,省去麻烦的极值判断

         2、初始化

         因为dp[i]取决于dp[i-1],所以dp[0][0] = 0

         3、写循环体

具体代码如下:

func isSubsequence(_ s: String, _ t: String) -> Bool {

        let sSize : Int= s.count

        let tSize:Int= t.count

        if sSize > tSize  {

            return false

        }

        //定义一个二维数组用来存储对应的状态,(此处声明的二维数据比原数组大1,因为后续循环要从1开始,预留一个空位,便于后续循环使用)

        var dp: [[Int]] = [[Int]](repeating: [Int](repeating:0, count: tSize+1), count: sSize+1)

        let sArray = Array(s)

        let tArray = Array(t)

        for j in 1 ... tSize {

            for i in 1 ... sSize {

                if tArray[j-1] == sArray[i-1] {

                    dp[i][j] = dp[i-1][j]+1

                }else{

                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])

                }

            }

        }

        return dp[sSize][tSize] == sSize

    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容