动态规划之最长上升子序列(贪心+二分法)

      动态规划算法和动态规划算法的区别:当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。运用贪心策略在每一次转化时都取得了最优解。问题的最优子结构性质是该问题可用贪心算法或动态规划算法求解的关键特征。贪心算法的每一次操作都对结果产生直接影响,而动态规划则不是。贪心算法对每个子问题的解决方案都做出选择,不能回退;动态规划则会根据以前的选择结果对当前进行选择,有回退功能。动态规划主要运用于二维或三维问题,而贪心一般是一维问题

      要求一样,就是在给定的数组里面找出最长子序列的长度(一般来说这个长度个数的可能子序列不唯一,但长度是唯一的),这篇文章主要讲解贪心+二分法来解决问题,如果刚接触,我建议先看入门篇-动态规划之最长子序列,里面有较详细的解释,这里主要是学习一个新的思想:我们现在利用一个数组来存放最长子序列 d[i](i 为当前长度),这个数组有这样的规定:不管怎么样,d[i]总的保存已遍历过最大的数,如果遇到比他小的,则在的d[i] 前面的数中,找到第一个比他大的值,然后替换(这里必须明白:替换并不会改变d数组的长度,所以在最后得到的结果是最长子序列长度的排好序的最小序列 ),如果比d[i]大直接接在后面即可,具体算法请看代码

#include<iostream>
using namespace std;
// 使用二分法的前提是 数组是已经排好序的(刚好在这里我们的d数组就是递增数组)
// 查找返回d数组中第一个比x大的值的下标
int er_method(int a[],int len,int x)
{
    int mid,l=1;
    while(l<=len)
    {
        mid = (l+len)/2;
        if(a[mid]<=x)
            l = mid+1;
        else
            len = mid-1;
    }
    return l;// 此时mid等于l
}
int main()
{
    int n;
    while(cin>>n)
    {
        //待测的数组-------    a
        //存放最长子序列---     d
        //记录最长子序列的长度-- len
        int a[101],d[101],len=1;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        d[1]=a[1];   // 第一个待测数字就d的第一个
        if(n<2)  // 如果待测数字只有一个 ,那就这个数字就是最长子序列
        {
            cout<<1<<endl;
            continue;
        }
        for(int i=2;i<=n;i++)
        {
            if(a[i]>d[len]) // 如果第 i个数大于d数组的最大的数,直接接在d数组的后面
                d[++len] = a[i];
            else    // 比d数组的最大数值小的的话,那就在d数组中找到一个比它大的数,替换掉
                d[er_method(a,len,a[i]] = a[i]; // 这一步不改变d 数组的长度
        }
        cout<<len<<endl;
    }
    return 0;
}

算法已经结束。这里必须再次强调,这种方法只能找出长度,但不能求解具体值是什么,它求出来的结果是 最长子序列长度的排好序的最小序列,请注意两个定语

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

memory_cood

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值