zoukankan      html  css  js  c++  java
  • 分享经典的动态规划问题(三)

    摘要:本系列最后一篇训练线性动规的基本套路的随笔,后面进阶更高级的动规类型入门(树形动规、区间动规、背包动规等).

    1.正文:以下主要通过几道典型的例题再训练一下线性动规的做法。

    复习一下:

      (1)题意分析;

      (2)基于分析数学建模;

      (3)判定是否可以符合使用动规的两大前置条件(最优子结构和无后效性),是则下一步,否则终止(非动规可以解决的问题,另寻他法);

      (4)动规基本三步曲:

        1)结合题意根据模型选择计算出比较合适的状态转移方程,归约初始的状态值,推导出终止(最终收敛)条件;

        2)迭代验证;

        3)选择合适的迭代次序实现状态转移方程的迭代和收敛;

      (5)编程实现。

    2.题目:

      上一篇是“子数组类”的例题给出“子数组”的定义:对于给定数组a[0..n],其中a[i..j](0<=i<=j<=n)为该数组的子数组;

      本篇类似地,有“子序列类”的例题给出“子序列”的定义:对于给定数组a[0..n],其中(a[i],..,a[j])(0<=i,..,j<=n且a[i]≠..≠a[j])为数组a的一组子序列;

      显然,子序列与子数组共同点在于都是有顺序要求(按数组元素排列顺序),区别在于子序列允许元素间不相邻,子数组必须相邻(连续性)。

     

    3.输入输出示例:

    1.最长公共子序列

    输入:

    [2, 1, 4, 3, 5, -1, 8]

    输出:  

    8

    2.最长递增子序列:

    输入:

    [2, 1, 4, 3, 5, -1, 8]

    输出:  4

    4.例程: 

    package com.algorithm;

    /**
    * 子序列类问题
    * 1.最长公共子序列;
    * 2.最长递增子序列;
    * 3.最长路径问题(明天会在评论附上)
    */
    public class DynamicProgrammingSolution {

    /**
    * 1.最长公共子序列
    * a.建模?不需要
    * b.定义max[i][j]为a[0..i]b[0..j]的最长公共子序列长度,显然状态转移方程有:
    * max[i][j] = max{max[i - 1][j], max[i][j - 1], max[i -1][j -1] + (a[i] == b[j] ? 1 : 0)}
    * max = max{max[i][j]}
    * 初始值为:max[0][j] = a[0] == b[j] ? 1:0 , 终止条件是遍历完成。
    * @param a
    * @param b
    * @return
    */
    private static int maxLenCommonSubSequence(int[] a, int[] b) {
    if (null == a || null == b) {
    return -1;
    }
    int[][] max = new int[a.length][b.length];
    int maxLen = 0;
    for (int i = 0; i < a.length; i++) {
    for (int j = 0; j < b.length; j++) {
    if (a[i] == b[j]) {
    max[i][j] = 1;
    }
    if (i > 0 && j > 0) {
    max[i][j] += max[i - 1][j - 1];
    }
    if (i > 0) {
    max[i][j] = Math.max(max[i][j], max[i - 1][j]);
    }
    if (j > 0) {
    max[i][j] = Math.max(max[i][j], max[i][j - 1]);
    }
    maxLen = Math.max(maxLen, max[i][j]);
    }
    }
    return maxLen;
    }

    /**
    * 2.最长递增子序列
    * a.建模?不需要
    * b.max[i]定义为a[i]为末尾元素的子序列中最长的递增子序列,故有方程:
    * max[i] = max{max[k]{a[k] < a[i]}}{k:0..i-1};
    * max = max{max[i]}
    * 初始值为max[i] = 1, 终止条件是正向迭代计算完成。
    * @param a
    * @return
    */
    private static int maxIncrementSubSequence(int[] a) {
    if (null == a) {
    return -1;
    }
    int maxLen = 0;
    int[] max = new int[a.length];
    for (int i = 0; i < a.length; i++) {
    //初始时a[i]本身就是一个递增序列
    max[i] = 1;
    //计算a[i]之前符合a[k]比a[i]小的最大的递增序列
    int leftMax = 0;
    for (int k = 0; k < i; k++) {
    if (a[k] < a[i]) {
    leftMax = Math.max(max[k], leftMax);
    }
    }
    //得到最终的迭代值
    max[i] += leftMax;
    //比较大小获取最大值
    maxLen = Math.max(maxLen, max[i]);
    }
    return maxLen;
    }


    public static void main(String[] strings) {
    int[] ints = {2, 1, 4, 3, 5, -1, 8};
    int[] int2 = {2, 1, 4, 3, 5, 2, 8};
    System.out.println(maxIncrementSubSequence(ints));
    System.out.println(maxLenCommonSubSequence(ints, int2));
    }


    }

    与上篇是兄弟篇,同样上述题目都已经建好模了,都是经典例题,比较简单,不再赘述,不懂的地方请认真看看注释能否释疑,有问题欢迎留言。

    5.总结:

     事实上,“子数组”、“子序列”这两个概念在数组类的题目有着挺高的曝光率,很多经典的题型都有它们的身影,建议初学者一定要区分好这两个概念。另外,这是近期最后一篇线性动规的归档,后面将进入树形动规的入门,希望有问题可以多多交流。

  • 相关阅读:
    安装TeX字体
    【数学】对数的底为什么不能为负数
    算法设计的要求
    Windows HTTP Services
    为什么分母不能为0
    循环小数怎样变分数
    在win7环境下批量修改文件权限
    算法复杂度的极限证明
    深入理解 【有理数】、【无理数】、【虚数】
    kettle连接sqlserver
  • 原文地址:https://www.cnblogs.com/kentkit/p/13061960.html
Copyright © 2011-2022 走看看