快排思想求解第k小
阿新 • • 發佈:2018-12-24
思路1:基於快排每次都會確定一個最終元素位置,下面程式碼則採用這種思想編寫。
思路2:同樣基於快排,每次劃分後看左邊區間元素個數是否大於k個,若左邊區間元素個數大於k個則在左區間找第k大元素,若左邊區間個數小於k個,這時假設左邊有len個元素,這時候在右邊區間找第k-len+1個即可。
注:有不正當地方歡迎指出!
程式碼:
/* 快排思想求第k小,時間複雜度O(n),空間O(1) 測試資料: 5 3 2 1 3 5 4 5 3 1 2 3 1 4 */ #include<bits/stdc++.h> using namespace std; const int maxn=1005; int a[maxn]; int ans,n; int partion(int l,int r) { int i=l,j=r; int temp=a[l]; while(i<j) { while(i<j&&a[j]>=temp) j--; if(i<j) a[i]=a[j]; while(i<j&&a[i]<=temp) i++; if(i<j) a[j]=a[i]; } a[i]=temp; return i;//返回每次劃分元素位置 } int quickSort(int l,int r,int k) { int mid=partion(l,r); if(mid==k) return a[k]; if(mid>k) return quickSort(l,mid-1,k); if(mid<k) return quickSort(mid+1,r,k); } int main() { int k; while(scanf("%d%d",&n,&k)!=EOF) { ans=0; for(int i=1; i<=n; i++) scanf("%d",&a[i]); ans=quickSort(1,n,k); printf("%d\n",ans); } return 0; }
下面依照上面思想O(n)將一個數組劃分為這樣的兩個集合:設集合A元素個數為n1,集合內元素和為sum1,集合B元素個數為n2,集合內元素和為sum2,兩集合滿足|n1-n2|儘可能小的前提下|sum1-sum2|儘可能大。
程式碼:
/* 時間複雜度O(n),空間O(n) */ #include<bits/stdc++.h> using namespace std; const int maxn=1000; int a[maxn],A[maxn],B[maxn]; int n; int Partion(int l,int r) { int i=l,j=r; int temp=a[l]; while(i<j) { while(i<j&&a[j]>=temp) j--; if(i<j) a[i]=a[j]; while(i<j&&a[i]<=temp) i++; if(i<j) a[j]=a[i]; } a[i]=temp; return i; } void quickSort(int l,int r,int k) { int mid=Partion(l,r); if(mid==k) { for(int i=1;i<mid;i++) A[i]=a[i]; for(int i=mid;i<=n;i++) B[i]=a[i]; return; } if(mid>k) quickSort(l,mid-1,k); if(mid<k) quickSort(mid+1,r,k); } int main() { int k; while(scanf("%d",&n)!=EOF) { if(n%2==0) k=(n>>1)+1; else k=(n+1)>>1; for(int i=1;i<=n;i++) scanf("%d",&a[i]); quickSort(1,n,k); for(int i=1;i<k;i++) printf("%d ",A[i]); printf("\n"); for(int i=k;i<=n;i++) printf("%d ",B[i]); printf("\n"); } return 0; }