传统弱校HFUT的蒟蒻,真相只有一个

白板编程常见题目总结

目录

一、二分查找实现 upper_bound、lower_bound

二、排序——快排

三、排序——归并

四、排序——堆排

五、排序——冒泡

六、最大子数组和

七、最大子数组积

七、TopK问题

 

 

一、二分查找实现 upper_bound、lower_bound

记住两个函数的含义upper_bound找到大于目标值的第一个位置,lower_bound找到大于等于目标值的第一个位置

int lower_bound(vector<int>&num,int head,int tail,int &val)
{
    int mid=int((head+tail)/2),out=-1;
    if(head==tail||head+1==tail)
    {
        if(num[head]==val)
            return head;
        else if(num[tail]==val)
            return tail;
        else
            return -1;
    }
    if(num[mid]<val)
        out=lower_bound(num,mid,tail,val);
    else
        out=lower_bound(num,head,mid,val);
    return out;
}
int upper_bound(vector<int>&num,int head,int tail,int &val) { int mid=int((head+tail)/2),out=-1; if(head==tail||head+1==tail) { if(num[head]!=val) return head; else if(num[tail]!=val) return tail; else return -1; } if(num[mid]<=val) out=upper_bound(num,mid,tail,val); else out=upper_bound(num,head,mid,val); return out; }

 二、排序——快排

具体思路见 https://www.cnblogs.com/dzzy/p/12241585.html

时间:O(N*logN) ;空间:O(N*logN);不稳定

void quick_sort(vector<int>&num,int start,int end)
{
    int head=start,tail=end,hole=start;//头指针 尾指针 坑 。初始 head=start,tail=end,hole=start
    int tmp_cmp=num[hole];//取出第一个坑处元素值//坑可能在头处,可能在尾处,初始在头处
    while(head<tail)//终止条件
    {
        if(hole==head)//坑在头处,和尾指针比较
        {
            if(tmp_cmp>num[tail])//tail处小,交换坑的位置
            {
                num[hole]=num[tail];
                hole=tail;
                head++;
            }
            else//tail处大,移动tail的位置
            {
                tail--;
            }
        }
        else if(hole==tail)//坑在尾处,和头指针比较
        {
            if(tmp_cmp<num[head])//head处大,交换坑的位置
            {
                num[hole]=num[head];
                hole=head;
                tail--;
            }
            else//head处小,移动head的位置
            {
                head++;
            }
        }
    }
    num[head]=tmp_cmp;
    //此时确认head==tail处正是这一个元素的真实位置,借此二分继续查找
    if(start<=head-1)
        quick_sort(num,start,head-1);
    if(head+1<=end)
        quick_sort(num,head+1,end);
    return;
}

三、排序——归并

时间:O(N*logN);空间:O(N);稳定

void merge(vector<int>&num,vector<int>&tmp,int head,int mid,int tail)
    {
        int i=head,j=mid+1;//num数组的两个指针
        int x=head;//tmp数组指针
        while(i<=mid&&j<=tail)
        {
            if(num[i]<=num[j])
                tmp[x++]=num[i++];
            else
                tmp[x++]=num[j++];
        }
        while(i<=mid)
            tmp[x++]=num[i++];
        while(j<=tail)
            tmp[x++]=num[j++];
        for(i=head;i<=tail;i++)
            num[i]=tmp[i];      
    }
    void Merge_search(vector<int>&num,vector<int>&tmp,int head,int tail)
    {
        int mid=int((head+tail)/2);
        if(head<tail)
        {
            Merge_search(num,tmp,head,mid);
            Merge_search(num,tmp,mid+1,tail);
            merge(num,tmp,head,mid,tail);
        }
    }

 四、排序——堆排

这里讲的很好,参考1 参考2

时间:O(N*logN);空间O(1);不稳定

const int INF = 0x3f3f3f3f;
void rbulid_heap(vector<int>&num,int start,int end)//重构大根堆
{
    for(int i=start;i<end;)
    {
        int L_n=-INF,R_n=-INF;
        if(i*2+1<=end)
            L_n=num[i*2+1];
        if(i*2+2<=end)
            R_n=num[i*2+2];
        if(num[i]<L_n&&L_n>=R_n)//根小于左叶子 交换
        {
            int tmp=num[i];//交换
            num[i]=num[i*2+1];
            num[i*2+1]=tmp;
            i=i*2+1;
        }
        else if(num[i]<R_n&&R_n>L_n)//根小于右叶子 交换
        {
            int tmp=num[i];//交换
            num[i]=num[i*2+2];
            num[i*2+2]=tmp;
            i=i*2+2;
        }
        else
            break;
    }
    return;
}
void Heap_sort(vector<int>&num)
{
    int end=num.size()-1;
    //将指定范围内构建成大根堆 根在0处 注:需要从叶子向上更新才能保证有序
    for(int i=end;i>=0;i--)
        rbulid_heap(num,i,end);
    for(;end>0;end--)//依次缩小堆的范围
    {
        rbulid_heap(num,0,end);
        int tmp=num[0];//交换
        num[0]=num[end];
        num[end]=tmp;
    }
    return;
}

 五、排序——冒泡

时间:O(n^2);空间:O(1);稳定

void papaw(vector<int>&num)
{
    int size=num.size(),tmp;
    for(int i=0;i<size-1;i++)
    {
        int lable=0;
        for(int j=1;j<size-i;j++)
        {
            if(num[j-1]>num[j])//交换 冒泡
            {
                tmp=num[j-1];
                num[j-1]=num[j];
                num[j]=tmp;
                lable=1;
            }
        }
        if(lable==0)
            break;
    }
    return;
}

 六、最大子数组和

主要考虑前面的加和为+对当前有贡献、加和为-对当前有负贡献,因此只需记录最大加和

dp[j]=max{dp[j-1]+num[i],num[i]}

int maxSubArray(vector<int> nums) {
    int size=nums.size();
    if(size==0)
        return 0;
    int maxl=nums[0];
    for(int i=1;i<=size-1;i++)
    {
        nums[i]=max(nums[i-1]+nums[i],nums[i]);
        maxl=max(maxl,nums[i]);
    }
    return maxl;
}

七、最大子数组积

不同于加和,当前最大乘积有可能是一个很小的负数×一个负数得到的,要维护一个max一个min获得当前最大成绩
void max_mult(vector<int>&num)
{
    int size=num.size(),MAX_RESULT;
    vector<int>maxl(size,0);
    vector<int>minl(size,0);
    maxl[0]=minl[0]=MAX_RESULT=num[0];
    for(int i=1;i<size;i++)
    {
        maxl[i]=max(max(maxl[i-1]*num[i],minl[i-1]*num[i]),num[i]);
        minl[i]=min(min(maxl[i-1]*num[i],minl[i-1]*num[i]),num[i]);
        MAX_RESULT=max(MAX_RESULT,maxl[i]);
    }
    return MAX_RESULT;
}

 七、TopK问题

 TopK问题一般答两种思路,参考

1、一种是基于快排思想的topk二分查找,一轮排序后确定的一个元素位置是真实的位置,这个元素i左面的都比它小、右边的都比它大,如果i==k那么找到了topk的位置;如果i<k那么topk位置一定大于i,用右边部分查找top(k-i)成为一个子问题;如果i>k那么继续在左边寻找topk;

2、最好的思路是堆排序,维护一个小根堆,每次比较当前元素和根的大小,大于根,那么就把根替换成当前元素,重新维护堆的顺序,再次比较。好处,可以处理流式数据,不需要预先把所有数据都存在内存中。

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
void build_heap(vector<int>&num,int start,int end)//重建堆 维护顺序
{
    for(int i=start;i<end;)
    {
        int L_n=INF,R_n=INF;
        if(i*2+1<=end)
            L_n=num[i*2+1];
        if(i*2+2<=end)
            R_n=num[i*2+2];
        if(num[i]>L_n&&L_n<R_n)//根大于左叶子 交换
        {
            int tmp=num[i];//交换
            num[i]=num[i*2+1];
            num[i*2+1]=tmp;
            i=i*2+1;
        }
        else if(num[i]>R_n&&R_n<L_n)//根大于右叶子 交换
        {
            int tmp=num[i];//交换
            num[i]=num[i*2+2];
            num[i*2+2]=tmp;
            i=i*2+2;
        }
        else
            break;
    }
}
void print_heap(vector<int>&num,int k)
{
    for(int i=0;i<k;i++)
        cout<<num[i]<<" ";
    cout<<endl;
}
int main()
{
    int K,n,tmp;
    cin>>K>>n;//topK - 数组规模n
    vector<int>num(n,-INF);//用数组模拟堆
    for(int i=0;i<K;i++)//先用k个数据构建堆
        cin>>num[i];
    for(int i=K-1;i>=0;i--)//初始化堆
        build_heap(num,i,K-1);
    for(int i=K;i<n;i++)
    {
        cin>>tmp;
        if(tmp>num[0])
        {
            num[0]=tmp;
            build_heap(num,0,K-1);
        }
    }
    print_heap(num,K);
    return 0;
}
/*
5 10
8 2 5 9 6 10 12 9 8 13
*/

 

 

 

posted @ 2020-09-14 15:02  未名亚柳  阅读(325)  评论(1编辑  收藏  举报