[python] 2019-03-09

动态规划


1. 给定一个矩阵m,从左上角开始每次只能向右或者向下走,最后到达右上角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。如果给定的m如大家看到的样子,路径1,3,1,0,6,1,0是所有路径中路径和最小的,所以返回12。

1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0

假设矩阵m的大小为M*N,行数为M,列数为N。生成大小和m
一样的矩阵dp,行数为M,列数为N,dp[i][j]的值表示从左上角,也就是(0,0)位置走到(i,j)位置的最小路径和。

dp[i][j]=m[i][j]+min{dp[i-1][j], dp[i][j-1]}

2. 给定数组arr,返回arr的最长递增子序列长度。比如arr=[2,1,5,3,6,4,8,9,7],最长递增子序列为[1,3,4,8,9],所以返回这个子序列的长度5.

arr:2 1 5 3 6 4 8 9 7
dp: 1 1 2 2 3 3 4 5 4

dp[i]表示在必须以arr[i]这个数结尾的情况下,arr[0,…i]中的最大递增子序列的长度。

dp[i]=max{dp[j]+1(0<=j<i, arr[j]<arr[i])}

3. 给定两个字符串str1和str2,返回两个字符串的最长公共子序列。例如,str1="1A2C3D4B56",str2="B1D23CA45B6A","123456"或者"12C4B6"都是最长公共子序列,返回哪一个都行。

假设str1的长度为M,str2的长度为N,生成大小为M*N的矩阵dp。dp[i][j]的含义是str1[0...i]与str2[0...j]的最长公共子序列的长度。

dp求法如下:

  1. 矩阵dp第一列,即dp[i][0],代表str1[0...i]与str2[0]的最长公共子序列长度,str2[0]只有一个字符,所以dp[i][0]最大为1.
    一旦dp[i][0]被设为1,则令dp[i+1...M][0]全部为1
  2. 矩阵dp第一行,即dp[0][j],与步骤1同理。
    如果str1[0]==str2[j],则令dp[0][j]为1
    一旦dp[0][j]被设为1,则令dp[0][j+1...N]全部为1
  3. 其他位置,dp[i][j]的值只可能来自以下三种情况:
    情况一:可能是dp[i-1][j]的值
    情况二:同理可知,可能是dp[i][j-1]的值
    情况三:如果str1[i]==str2[j],还可能是dp[i-1][j-1]+1的值

三个最大的值,取一个即可。

4. 一个背包有一定的承重W,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。

假设物品编号从 1 到 n,一件一件物品考虑是否加入背包。
假设 dp[x][y] 表示前 x 件物品,在不超过重量 y 的时候的最大价值。枚举一下第 x 件物品的情况:

情况一:如果选第 x 件物品,则前 x - 1 件物品得到的重量不能超过 y - w[x]。
情况二:如果不选 x 件物品,则前 x - 1 件物品得到的重量不能超过 y。
无论哪种情况,我们都需要去求解 x - 1 件物品的情况。

所以,dp[x][y] 可能等于 dp[x-1][y],也就是不取第 x 件物品的时候,价值和之前的一样。
也可能是 dp[x-1][y - w[x]] + v[x],也就是决定拿第 x 件物品的情况,当然会加上 x 物品的价值。
两种可能性中,应该选择价值最大的那个,状态转移方程如下:
dp[x][y] = Max{dp[x-1][y], dp[x-1][y-w[x]]+v[x]}

对于 dp 矩阵来说,行数是物品的数量 n,列数是背包的最大承重 w。然后再从左到右,从上到下计算所有的 dp 的值即可。

该矩阵中的每个值的求解都代表一个更小的背包问题。
初始情况一:对于第0列,它的含义是背包的容量为0。此时物品的价值呢?没有。因此,第一列都填入0。
初始情况二:对于第0行,它的含义是屋内没有物品。那么没有任何物品的背包里的价值多少呢?还是没有!所有都是0。
所以我们可以把这个矩阵的大小定义为 dp[n+1][y+1],从第二行第二列也就是 dp[1][1] 的位置开始带入状态转移方程进行计算,其实这也解决了我长期以来对这个矩阵的行列都+1的困扰。

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @param V: Given n items with value V[i]
     * @return: The maximum value
     */
    public int backPackII(int m, int[] A, int[] V) {
        // 1.定义状态矩阵,dp[i][j]表示在0..i个物品中不超过j重的情况下的背包的最大价值
        int[][] dp = new int[A.length + 1][m + 1];
        // 2.状态转移方程:dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-A[i-1]] + V[i-1])
        for (int i = 1; i <= A.length; i++) {
            for (int j = 1; j <= m; j++) {
                dp[i][j] = dp[i-1][j];
                if (j >= A[i-1]) {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-A[i-1]] + V[i-1]);
                }
            }
        }
        return dp[A.length][m];
    }
}

6. 给定两个字符串str1和str2,在给定三个整数ic,dc和rc,分别代表插入、删除和替换一个 字符,返回将str1编辑成str2的最小代价。

解题方法:

动态规划。首先生成大小为(M+1)X(N+1)的矩阵dp。

假设str1="av=b12cd3", str2="abcdf"。dp[i][j]表示str1[0:i]编辑成str2[0:j]的最小代价。计算结果如下:



计算步骤:
1、dp[0][0]表示str1空的子串编辑成str2空的子串的代价为0

2、矩阵dp第一列即dp[0:M-1][0], dp[i][0] 表示str1[0:i-1]编辑成空串的最小代价,即把str1[0:i-1]中所有字符删掉的代价,所以dp[i][0] = dc * i

3、矩阵第一行即dp[0][0:N-1], dp[0][j]表示空串编辑成str2[0:j-1]的最小代价,即向空串中添加字符的代价,所以dp[0][j] = ic * j

4、其他位置,从左到右,从上到下计算,dp[i][j]的值可能来自于一下四种情况:
(1)str1[0:i-1]先编辑成str1[0:i-2],即先删除字符str1[i],然后由str1[0:i-2]编辑成str2[0:j-1],dp[i-1][j] 表示str1[0:i-2]编辑成石头人[0:j-1]的最小代价,那么dp[i][j]可能等于dc + dp[i-1][j]
(2)str1[0:i-1]可以先编辑成str2[0:j-2],然后向str2[0:j-2]插入字符str2[j-1],编辑成str2[0:j-1],dp[i][j-1]表示str1[0:i-1]编辑成str2[0:j-2]的最小代价,那么dp[i][[j]可能等于dp[i][j-1] + ic;
(3) 如果str1[i-1] != str2[j-1], 可以先将str1[0:i-2]编辑成str2[0:j-2],然后将str1[i-1]替换成str2[j-1],dp[i-1][j-1]表示将str1[0:i-2]编辑成str2[0:j-2]的最小代价,那么dp[i][j]可能等于dp[i-1][j-1]+rc
(4)如果str1[i-1] == str2[j-1], 则此时dp[i][j] = dp[i-1][j-1]
以上四种可能的值中,选最小值作为dp[i][j]的值。

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

推荐阅读更多精彩内容

  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,339评论 0 2
  • 动态规划(Dynamic Programming) 本文包括: 动态规划定义 状态转移方程 动态规划算法步骤 最长...
    廖少少阅读 3,270评论 0 18
  • 【程序1】 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔...
    开心的锣鼓阅读 3,311评论 0 9
  • 两道题都是动态规划问题,以下内容来自牛客网左神的课和书,我作为知识的搬运工,正在试图去领会程序的玄妙~~ 两个题目...
    陌北有棵树阅读 2,278评论 0 0
  • 豆瓣评分:9.0(24367人评价) 可读性:☆☆☆ 短篇小说,阅读需3小时,成本较低 加缪代表作之一(局外人、鼠...
    韧世大帝阅读 820评论 0 1