算法笔记系列:4.5 二分 4.6 two pointers

4.5.1 二分查找

  • 基于有序序列的查找算法,时间复杂度为O(logn)
  • 高效之处在于每一步都可以去除当前区间中的一半元素
# include<cstdio>
int binary_search(int a[],int left, int right,int x){
    int mid;
    while (left<=right){
        mid=(left+right)/2;
        if (a[mid]==x) return mid;
        else if (a[mid]>x) right=mid-1;
        else left=mid+1;
    }
    return -1;
}
int main(){
    const int n=10;
    int A[n]={1,3,4,6,7,8,10,11,12,15};
    printf("%d %d\n",binary_search(A,0,n-1,6),binary_search(A,0,n-1,9));
    return 0;
}

注意: left+right可能会超出Int的范围导致溢出,所以最好写left+(right-left)/2

4.5.2 二分法拓展

当查询的不是整数时,例如通过二分法计算$\sqrt{2}$

# include<cstdio>
const double eps=1e-5;
double f(double x){
    return x*x;
}
double calsqrt(){
    double left=1,right=2;
    double mid;
    while (right-left>eps){
        mid=left+(right-left)/2;
        if (f(mid)>2) right=mid;
        else left=mid;
    }
    return mid;
}

4.5.3 快速幂

用二分法的思想求幂

  • 递归写法

    typedef long long LL;
    //求a^b%m,递归写法
    LL binary_row(LL a,LL b,LL m){
        if (b==0) return 1;
        if (b%2==1) return a*binary_row(a,b-1,m);
        else{
            LL mul=binary_row(a,b/2,m);
            return mul*mul%m;
        }
    
    }
    
  • 迭代写法

    typedef long long LL;
    LL binary_pow(LL a,LL b, LL m){
        LL ans=1;
        while (b>0)
        {
            if (b&1) ans=ans*a%m;
            a=a*a%m;
            b >>=1;
        }
        return ans;
        
    }
    

4.6.1 什么是two pointers

利用有序序列的枚举特性,使用两个下标对序列进行扫描的思想

4.6.2 归并排序

归并排序复杂度为O(nlogn),2-路归并排序的原理是将序列两两分组,组内进行单独排序,然后再合并,以此类推

const int maxn=100;
void merge(int A[],int L1,int R1, int L2,int R2){
    int i=L1,j=L2;
    int temp[maxn],index=0;
    while(i<=R1&&j<=R2){
        if (A[i]<=A[j]) temp[index++]=A[i++];
        else temp[index++]=a[j++];
    }
    while(i<=R1) temp[index++]=A[i++];
    while (j<=R2) temp[index++]=A[j++];
    for (i=0;i<index;i++){
        A[L1+i]=temp[i];
    }
    
}

void mergeSort(int A[],int left, int right){
    if (left<right){
        int mid=(left+right)/2;
        mergeSort(A,left,mid);
        mergeSort(A,mid+1,right);
        merge(A,left,mid,mid+1,right);
    }
}

4.6.3 快速排序

平均时间复杂度在O(nlogn),原理是选定一个元素作为主元 保证左边元素不大于它,右边元素不小于它

int partition(int A[],int left,int right){
    int temp=A[left];
    while(left<right){
        while(left<right&&A[right]>temp) right--;
        A[left]=A[right];
        while(left<right&&A[left]<=temp) left++;
        A[right]=A[left];
        
    }
    A[left]=temp;
    return left;
}

4.7.1 打表

  • 在程序中一次性计算出所有需要用到的结果,之后的查询直接取这些结果
  • 在程序B中分一次或多次计算出所有用到的结果,手工把结果写在程序A的数组中,然后在程序A就可以直接使用这些结果
  • 对一些感觉不太会做的题目,先用暴力程序计算小范围数据的结果,然后找规律,或许能发现一些“蛛丝马迹”

4.7.2 活用递推

【PAT A1093】

# include<cstdio>
# include<cstring>
# include<iostream>
using namespace std;
const int mod=1000000007;
const int maxn=100010;
int left_num_p[maxn]={0};
int main(){
    char str[maxn];
    cin.getline(str,sizeof(str));
    int len=strlen(str);
    for (int i = 0; i < len; i++)
    {
        if(i>0) left_num_p[i]=left_num_p[i-1];
        if(str[i]=='P') left_num_p[i]++;
    }
    int ans=0,num_right_T=0;
    for(int i=len-1;i>=0;i--){
        if(str[i]=='T') num_right_T++;
        else if(str[i]=='A') ans=(ans+left_num_p[i]*num_right_T)%mod;
    }
    printf("%d\n",ans);
    return 0;

}

4.7.3 随机选择算法

如何从无序数组中求出第K大的数,原理类似于快速排序算法,对主元进行排序完后,主元就是第M大的数,判断M和K的大小缩小范围,然后再一次排序,直到M=K就找到了,时间复杂度为O(n)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值