2019年7月24日学习日记(二分、排序)

一、二分
1.整数集合上的二分
1)在单调增序列a中查找>=x的数最小的一个:

while(l<r)
{
    int mid=(l+r)/2;
    if(a[mid]>=x) r=mid;
    else l=mid+1;
}
return a[l];

2)在单调增序列a中查找<=x的数中最大的一个

while(l<r)
{
    int mid=(l+r+1)/2;
    if(a[mid]<=x) l=mid;
    else r=mid-1;
}
return a[l];

根据不同的问题合理选择r=mid,l=mid+1,mid=(l+r)/2或者l=mid,r=mid-1,mid=(l+r+1)/2中的一种
2.实数域上的二分:
需要确定好精度eps,以l+eps<r为循环条件:

while(l+eps<r)
{
    double mid=(l+r)/2;
    if(calc(mid)) r=mid;
    else l=mid;
}

也可以用循环固定次数的二分法:(精度往往比比上面的高)

for(int i=0;i<100;i++)
{
    double mid=(l+r)/2;
    if(calc(mid)) r=mid;
    else l=mid;
}

3.三分求单峰函数极值:
函数极值左边严格递增(或递减),极值右边严格递减(或递增)

double lmid, rmid;
while ( low + eps < high )
{
    lmid = (low + high) / 2;
    rmid = (lmid + high ) / 2;
    double clmid = cal(lmid);
    double crmid = cal(rmid);
    if ( clmid > crmid ) 
		    high = rmid;
    else 
        low = lmid;
}

二、排序
1.排序种类:
1)选择排序、插入排序、冒泡排序
2)堆排序、归并排序(可以用于求解逆序对)、快速排序
3)计数排序、基数排序、桶排序(这三种时间复杂度最低)
2.离散化:
把无穷多个元素映射为有限的集合的方法。
当问题有n个数,但是求解只涉及m个数,可以将这m个数与1~m建立一一映射关系。可以将这m个数去重,存到b数组中,建立b[i]与i的关系,只需要在数组中b查找所需要的数即可。

void discrete()
{
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
        if(i==1||a[i]!=a[i-1])
           b[++m]=a[i];
}
void query(int x)
{
    return lower_bound(b+1,b+m+1,x)-b;
}

3.中位数:
对于许多问题求最优解就是求解中位数。
4.第k大数:
实际上运用了快速排序的思想。
选取一个数x做基准,<x放在左边,>x放在右边。然后判断x的位置与k的关系,若>k则在左边继续操作,若<k在右边继续操作,依此类推,时间复杂度比快速排序小,为O(n)。
5.逆序对
运用了归并排序的思想,将所有的数一步步二分为一个个的小区间,从小区间到大区间判断逆序对的个数,返回上一级的区间。

void merge(int l,int mid,int r)
{
    //合并a[l~mid]与a[mid+1~r]
    //a是待排序数组,b是临时数组,cnt是逆序对个数
    int i=l,j=mid+1;
    for(int k=l;k<=r;k++)
        if(j>r||i<=mid&&a[i]<a[j])
            b[k]=a[i++];
    for(int k=l;k<=r;k++)
        a[k]=b[k];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值