• 动态规划总结


    问题1:最长上升子序列问题(LIS)

    分析:设d(i)为以i为结尾的最长上升子序列的长度,则d(i)=max{ 1 , d(j)+1} ( j的值为1,2,3,...,i-1且Aj<Ai ),最终答案是max{d(i)}。如果LIS中的相邻元素可以相等,把   小于号改成等于号即可。算法的时间复杂度为O(n^2)

            一种时间复杂度是O(nlogn)的方法。假设已经计算出的两个状态a和b满足Aa<Ab且d(a)=d(b),则对于后续所有状态i(即i>a且i>b)来说,a并不会比b差——如果b满足 Ab<Ai的条件,a也满足,且二者的d值相同;但反过来却不一定了,a满足Aa<Ai的条件时,b却不一定满足。换句话说,如果我们只保留a,一定不会丢失最优解。

            这样对于相同的d[]值,只需保留A最小的一个。对于d[i]=k,我们用g[k]表示满足d[]值等于k的所有A[i]中的最小值。即g[k]=min{A(i)}(d[i]=k)。

            设当前已经求出的最长上升子序列长度为len,先判断A[i]与g[len],若A[i]>g[len],把A[i]接在g[len]之后得到一个更长的上升子序列,len=len+1,g[len]=A[i];否则, 在g[1]...g[len]中找到最大的j,满足g[j]<A[i],令k=j+1,将A[i]接在g[j]之后得到一个更长的上升子序列,更新g[k]=A[i]。最后,len即为所要求的最长上升子序列。

            在上述算法中,如果用朴素的顺序查找g[1]...g[len],由于有O(n)个元素要查找,每次查找的时间复杂度是O(n),所以整体复杂度是O(n^2)。但由于g[len]有如下特点:g[1]<g[2]<...<g[len],可以用二分查找,整个算法时间复杂度降为O(nlogn)

            for(int i=1;i<=n;i++) g[i]=INF;

            for(int i=0;i<n;i++){

            int k=lower_bound(g+1,g+1+n,A[i]) - g;

            d[i]=k;

            g[k]=A[i];

            }

    函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置

    举例如下:
    一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标

    pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
    pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
    pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
    所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~
    返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置

         

  • 相关阅读:
    Python编程题32最小栈
    Python编程题31用列表实现队列
    Python编程题34用队列实现栈
    Python编程题40验证字母表的顺序
    Python编程题36三个数的最大乘积
    Python编程题39所有奇数长度子列表的和
    RTX 3090的深度学习环境配置指南:Pytorch、TensorFlow、Keras。配置显卡
    python numpy实现SVD 矩阵分解
    linux安装tomcat部署静态网页
    python使用deepwalk模型算节点相似度
  • 原文地址:https://www.cnblogs.com/sage-blog/p/3648291.html
Copyright © 2020-2023  润新知