2019年3月27日训练日记

今天做了一道最长上升子序列的题还有一道简单的dp。
然后对dp进行了一些思考与反思
动态规划的核心思想: 重复, 最优, 子问题 递归转递推。
最近做的这些题很多都是01背包的,自己对01背包一开始很不理解,想了很久没想明白这个算法的真正原理,寒假了把那一张二维数组的图画了三四遍,前几天又把正推逆推画了几遍,其实在面对一个自己不是很理解的问题时,我感觉自己手动去模拟几遍是一个很好的方法,很大程度上帮助我们去理解到底为什么这样做,算法这样设计的内涵在哪里。dp难就难在一个状态转移方程,大部分题都是根据题意写出几层循环,然后在按照要求来确定最优解,寻找状态转移方程,但是自己找状态转移方程却是非常吃力,我哥哥告诉我刚开始学dp都是这个样子,熟练了就好,多做题,多看代码,勤思考为什么要这样写状态转移方程,慢慢就好了,看来还是自己做题少,努力刷题。
最长上升子序列
一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
状态设计:F[i]代表以A[i]结尾的LIS的长度
状态转移:F[i]=max{F[j]+1}(1<=j< i,A[j]< A[i])
边界处理:F[i]=1(1<=i<=n)
时间复杂度:O(n^2)
伪代码:

 for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[j]<a[i]) f[i]=max(f[i],f[j]+1);
    for(int i=1;i<=n;i++) 
        ans=max(ans,f[i]);

其实思想很简单就是我们需要考虑的只有最后选择的一个数,
前面已经选择的数的更改是不会影响到最终的长度的,反而如果前面的数一直更改到了最后一个.说明这里用一个更小的数将最后一个数给替代了, 因为对于后面我们不知道的序列, 为了达到最长, 我们当前选择的这个数当然越小越好.
还有一种方法就是贪心+二分也可以做出来,时间可能会长一点。

猜你喜欢

转载自blog.csdn.net/qq_43627087/article/details/88858477