算法模板复习 | 青训营笔记

32 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第-2 天

  1. 快速排序求第k小的数

image.png

#include<iostream>
using namespace std;

const int N = 1e5+10;

int q[N],n,k;

int quick_sort(int l, int r, int k){
    if(l>=r) return q[l];
    int i=l-1,j=r+1,x=q[l];
    while(i<j){
        while(q[++i]<x);
        while(q[--j]>x);
        if(i<j) swap(q[i],q[j]);
    }
    int s = j-l+1;
    if(s>=k) return quick_sort(l,j,k);
    else return quick_sort(j+1,r,k-s);
}

int main(){
    cin>>n>>k;
    for(int i=0;i<n;i++) cin>>q[i];
    int res = quick_sort(0,n-1,k);
    cout<<res<<endl;
}
如果求第k大的数只需修改快排比较部分,改为从大到小的排序。即

while(q[++i]>x);

while(q[--j]<x);

2. 归并排序求逆序对数

image.png

思路:利用归并分治递归的思想,逆序对分布有三种情况:第一是全部在左边,第二是全部在右边,第三是第一个数在左边,第二个数在右边。前两个情况递归去找就行了,第三种在归并最后合并的时候,当q[i]>q[j]q[i,mid]>q[j]。这时有mid-i+1个逆序对。
#include<iostream>
using namespace std;

const int N = 1e5+10;

int q[N],tmp[N];

typedef long long ll;


ll merge_sort(int q[], int l, int r){
    if(l>=r) return 0;
    int mid = l+r>>1;
    ll res = merge_sort(q,l,mid) + merge_sort(q,mid+1,r);
    int i=l, j=mid+1, k=0;
    while(i<=mid && j<=r){
        if(q[i]<=q[j]) tmp[k++]=q[i++];
        else{
            // q[i,mid]>q[j]
            tmp[k++]=q[j++];
            res += mid-i+1;
        }
    }
    while(i<=mid) tmp[k++]=q[i++];
    while(j<=r) tmp[k++]=q[j++];
    for(int i=l,k=0;i<=r;i++,k++) q[i]=tmp[k];
    return res;
}

int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>q[i];
    ll res = merge_sort(q,0,n-1);
    cout<<res<<endl;
    return 0;
}