面試跟序列有關的問題匯總


  面試中比較多會出序列有關的面試題,所以就總結下

(1)一個長度N為的序列,求前K小的數

  1.排序 N*log(N)

  2.最大堆N*log(K)

  3.有平均時間復雜度O(n)的算法,因為我們可以在O(n)的時間內找到未排序數組里面第k小的數的值,然后再遍歷一下數組,把值小於等於第k小的全都輸出(感謝 huangnima)

(2)有兩個長度為N的有序序列A和B,在A和B中各任取一個數可以得到N^2個和,求這N^2個和中最小的N個。

  1.比較直觀的想法是將A與B的數字相加后排序,時間復雜度O(N*N*log(N*N))

  2.考慮到要求的是求最小的N個數字,所以從這里考慮優化,維護一個大小為N的最小堆 log(N),對於N^N個數字的選擇有沒有優化方法,有!

     可以把這些和看成n個有序表:

    – A[1]+B[1] <= A[1]+B[2] <= A[1]+B[3] <=…

    – A[2]+B[1] <= A[2]+B[2] <= A[2]+B[3] <=…

    –…

    – A[n]+B[1] <= A[n]+B[2] <= A[n]+B[3] <=…

    當然並不用計算所有的和

    綜上所述,可以采用K路歸並:

    就是最小堆的元素增加一個狀態量(下標),記錄當前列最小值所在位置,下次遍歷時從這里開始!

    總的時間復雜度O(N*log(N))

#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;

struct data{
    int v;
    int no;
    data(int tv,int tno){
        v=tv;
        no=tno;
    }
    friend bool operator <(data x,data y){
        return x.v>y.v;
    }
};

int n;
int A[100099];
int B[100099];
int minS[100099];//記錄最小的N個數字
int reD[100099];//記錄相對最小的那個數字在所在行當前遍歷的位置

int main()
{
    int n,m;
    while(scanf("%d",&n)!=EOF){
        int i;
        priority_queue<data>qq;
        for(i=1;i<=n;i++){
            scanf("%d",&A[i]);
        }
        for(i=1;i<=n;i++){
            scanf("%d",&B[i]);
        }

        for(i=1;i<=n;i++){
            qq.push(data(A[1]+B[i],i));
            reD[i]=1;
        }

        for(i=1;i<n;i++){
            minS[i]=qq.top().v;
            int no=qq.top().no;
            qq.pop();
            reD[no]++;
            qq.push(data(A[reD[no]]+B[no],no));
        }minS[i]=qq.top().v;

        for(i=1;i<=n;i++){
            printf("%d\n",minS[i]);
        }
    }

    return 0;
}
View Code

(3)有兩個有序序列長度分別N,M。在A和B中各任取一個數可以得到N*M個和,求這N*M個和某個數字K是第幾大的元素。

  1.暴力N*M排序,時間復雜度O(N*M*log(N*M))

  2.貪心的思想: 隨着i增大,j只會逐漸減小或不變,時間復雜度O(N+M)

  注意查詢的數字有多個相同數字的情況

#include<stdio.h>
int A[100099];
int B[100099];

int main()
{
    int n,m,k;
    while(scanf("%d",&n)!=EOF){
        int i,j;
        for(i=1;i<=n;i++){
            scanf("%d",&A[i]);
        }
        scanf("%d",&m);
        for(i=1;i<=m;i++){
            scanf("%d",&B[i]);
        }
        scanf("%d",&k);k--;
        j=m;
        int all=0;
        for(i=1;i<=n;i++){
            while(A[i]+B[j]>k){
                j--;if(j==0)break;
            }if(j==0)break;
            all+=j;
        }
        printf("%d\n",all+1);
    }

    return 0;
}
View Code

 (4)有兩個有序序列長度分別N,M。在A和B中各任取一個數可以得到N*M個和,求這N*M個中第K大的元素是

  Nmin,Mmin,Nmax,Mmax分別表示N,M的最小值域最大值 

  對[Nmin+Mmin,Nmax+Mmax]進行二分,二分出一個結果,判斷這個值是第幾大(第三個問題),再二分判讀直到出結果

  時間復雜度O(log(-Nmin-Mmin+Nmax+Mmax)*(N+M))

  提供練習的傳送門:http://ac.jobdu.com/problem.php?pid=1534

(5)查找一個數列中為K的個數有幾個

  1.如果有序 兩次二分,先找K最左端的位置,在二分k最右端的位置

#include<stdio.h>

int shu[1009];

int main()
{
    int n,i;
    while(scanf("%d",&n)!=EOF){
        for(i=1;i<=n;i++){
            scanf("%d",&shu[i]);
        }
        int f;
        scanf("%d",&f);
        int ll=1,rr=n,mid;
        while(ll<=rr){//盡量靠左
            mid=(ll+rr)/2;
            if(f<=shu[mid])rr=mid-1;
            else ll=mid+1;
        }
        int rll=ll,rrr;
        //printf("%d\n",ll);

        ll=1,rr=n;
        while(ll<=rr){//盡量靠右
            mid=(ll+rr)/2;
            if(f<shu[mid])rr=mid-1;
            else ll=mid+1;
        }
    //    printf("%d\n",rr);
        rrr=rr;

        if(shu[rll]!=f){
            printf("個數為0\n");
        }else{
            printf("個數為 %d\n",rrr-rll+1);
        }
    }

    return 0;
}
View Code

     2.如果無序,則線性遍歷

(6) 給定一個數字序列,查詢任意給定區間內數字的最小值。

  1.RMQ O(n*logn)

#include<stdio.h>
 
int A[100099],d[100099][20];
int n,m;
 
int min(int a,int b){
    return a<=b?a:b;
}
 
void RMQ_init(){
    int i,j;
    for(i=1;i<=n;i++)d[i][0]=A[i];
    for(j=1;(1<<j)<=n;j++){
        for(i=1;i+(1<<j)-1<=n;i++){
            d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
        }
    }
}
 
int RMQ_find(int ll,int rr){
    int k=0;
    while((1<<(k+1))<=(rr-ll+1))k++;
    return min(d[ll][k],d[rr-(1<<k)+1][k]);
}
 
int main(){
    while(scanf("%d",&n)!=EOF){
        int i,j;
        for(i=1;i<=n;i++){
            scanf("%d",&A[i]);
        }RMQ_init();
        scanf("%d",&m);
        int ll,rr;
        while(m--){
            scanf("%d%d",&ll,&rr);
            printf("%d\n",RMQ_find(ll,rr));
        }
    }
 
    return 0;
}
View Code

  2.線段樹 O(n*logn)

如果有相關的題目,會繼續更新


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM