題目鏈接:https://ac.nowcoder.com/acm/contest/5773/A
題目描述
給你一個長度爲n的序列,求序列中第k小數的多少。
輸入描述:
多組輸入,第一行讀入一個整數T表示有T組數據。
每組數據佔兩行,第一行爲兩個整數n,k,表示數列長度和k。
第二行爲n個用空格隔開的整數。
輸出描述:
對於每組數據,輸出它的第k小數是多少。
每組數據之間用空格隔開
輸入
2
5 2
1 4 2 3 4
3 3
3 2 1
輸出
2
3
,數列裏每個數都在int範圍內
知識點
1、算法改進要點
冒泡排序掃描過程中只對相鄰的兩個元素進行比較,因此在互換兩個相鄰元素時只能消除一個逆序。
快速排序一次交換可能消除多個逆序。
2.算法思想
從待排序記錄序列中選取一個記錄(通常選取第一個記錄)爲樞軸,其關鍵字設爲,然後將其餘關鍵字小於的記錄移到前面,而將關鍵字大於或等於的記錄移到後面,結果將待排序記錄序列分成兩個子表,最後將關鍵字爲的記錄插到其分界線的位置處。將這個過程稱爲一趟快速排序
3.算法步驟
假設待劃分序列爲r[low],r[low+1],…,r[high]。首先將基準記錄r[low]移至變量x中,使r[low]相當於空單元,然後反覆進行如下兩個掃描過程,直至low和high相遇。
(1)high從右向左掃描,直到r[high]<x時,將r[high]移至空單元r[low],此時r[high]相當於空單元。
(2)low從左向右掃描,直至r[low]>=x時,將r[low]移至空單元r[high],此時r[low]相當於空單元。
當low和high相遇時,r[low] (或r[high])相當於空單元,且r[low]左邊所有記錄的關鍵字均小於基準記錄的關鍵字,而r[low]右邊所有記錄的關鍵字均大於或等於基準記錄的關鍵字。最後將基準記錄移至r[low]中,就完成了一次劃分過程。
完整快速排序代碼:
int QKPass(int a[],int low,int high)
{
int x=a[low];//選擇基準記錄
while(low<high)
{
while(low<high&&a[high]>=x)
high--;//high從右到左找小於x的記錄
if(low<high)
{
a[low]=a[high];//找到小於x的記錄,則送入空單元r[low]
low++;
}
while(low<high&&a[low]<x)
low++;//low從左到右找大於或等於x的記錄
if(low<high)
{
a[high]=a[low];//找到大於或等於x的記錄,則送入空單元r[high]
high--;
}
}
a[low]=x;//將基準保存在low=high的位置
return low;//返回基準的位置
}
void QKSort(int a[],int low,int high)
{
if(low<high)
{
int pos=QKPass(a,low,high);
QKSort(a,low,pos-1);//劃分兩個子表
QKSort(a,pos+1,high);
}
}
題目分析:
1.
在進行快速排序的時候在對左右子表進行排序,判斷左子表元素的個數和k的關係。
例如:基準左邊的數都比基準小,若基準左邊的數的個數大於k,對於基準右邊的數我們就不用管了。
int finding(int low,int high,int k)
{
if(low==high)
return a[low];
int i=low,j=high;
int mid=(low+high)>>1;
int x=a[mid];
while(i<=j)
{
while(a[i]<x)
i++;
while(a[j]>x)
j--;
if(i<=j)
{
swap(a[i],a[j]);
i++;
j--;
}
}
if(k<=j)
return finding(low,j,k);
else if(k>=i)
return finding(i,high,k);
else
return a[k];
}
2.快讀操作
inline int read()
{
int x = 0, f = 1;///f判斷正負
char ch = getchar();
while(ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x<<1) + (x<<3) + (ch^48);//相當於x=x*10+ch,位移操作提高效率
ch = getchar();
}
return x * f;
}
完整代碼:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5*1e6+10;
int n,k,a[N];
inline int read()
{
int x = 0, f = 1;///f判斷正負
char ch = getchar();
while(ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x<<1) + (x<<3) + (ch^48);//相當於x=x*10+ch,位移操作提高效率
ch = getchar();
}
return x * f;
}
int finding(int low,int high,int k)
{
if(low==high)
return a[low];
int i=low,j=high;
int mid=(low+high)>>1;
int x=a[mid];
while(i<=j)
{
while(a[i]<x)
i++;
while(a[j]>x)
j--;
if(i<=j)
{
swap(a[i],a[j]);
i++;
j--;
}
}
if(k<=j)
return finding(low,j,k);
else if(k>=i)
return finding(i,high,k);
else
return a[k];
}
int main()
{
int t;
t=read();
while(t--)
{
n=read();
k=read();
for(int i=1; i<=n; i++)
a[i]=read();
cout<<finding(1,n,k)<<endl;
}
return 0;
}