面试中比较多会出序列有关的面试题,所以就总结下

(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

相关文章:

  • 2021-06-08
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-08-13
  • 2022-02-06
猜你喜欢
  • 2021-09-10
  • 2021-11-08
  • 2022-12-23
相关资源
相似解决方案