zoukankan      html  css  js  c++  java
  • 白板编程常见题目总结

    目录

    一、二分查找实现 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
    */
  • 相关阅读:
    time 时间模块的函数调用
    str 文本函数的调用
    批量分发公钥
    K8s集群部署(四)------ Flannel网络部署
    kuberbetes基础概念
    K8s集群部署(三)------ Node节点部署
    K8s集群部署(二)------ Master节点部署
    K8s集群部署(一)------ETCD集群部署
    日常更新脚本
    CentOS7系统安装
  • 原文地址:https://www.cnblogs.com/dzzy/p/13666748.html
Copyright © 2011-2022 走看看