第三章:查詢與排序(下)----------- 3.12 實踐_最小可用id是多少
最小可用ID:在非負陣列(亂序)中找到最小可分配的id(從1開始編號),資料量為1000000。
解法1:
暴力解法:O(N²)。從1開始依次探測每個自然數是否在陣列中。不推薦
解法2:
先排序,然後看哪個數“不在其位”。NlgN。
#include<iostream>
#include<algorithm>
using namespace std;
int find2(int arr[],int length){
sort(arr,arr+length);
int i=0;
while(i<length){
if((i+1)!=arr[i]){
return i+1;
}
i++;
}
return i+1;
}
int main(){
int arr[]={3,6,1,5,9,7,8};
int len=7;
cout<<find2(arr,len);
return 0;
}
結果:
解法3:
開闢輔助空間,Eg:若5出現,則標記輔助空間5號單元為1。
待求陣列,長度為n,最小可用ID不可能大於n+1。即 最小可用id<=n+1.
//虛擬碼:
helper=[A.length]
for(i 0...A.length-1){
helper[A[i]-1]=1;
}
for(i 0...A.length-1){
if(helper[i]==0)
return i+1;
}
return A.length+1
#include<iostream>
#include<algorithm>
using namespace std;
/*
改進1:
新建長為n+1的陣列F,初始值全為false,掃描原陣列中的元素,小於n則將F[A[i]]記錄為true
最後再掃描F,返回第一個為false的元素的下標,注:有點類似於計數排序O(n)但是浪費空間
*/
int find3(int arr[],int length){
int n=length;
int helper[n+1];
//*helper陣列初始化
for(int i=1;i<n+1;i++){
helper[i]=0;
}
for(int i=0;i<n;i++){
if(arr[i]<n+1){
helper[arr[i]]=1; //1:代表出現;0:代表未出現
}
}
for(int i=1;i<=n;i++){
if(helper[i]==0){
return i;
}
}
return n+1;
}
int main(){
int arr[]={3,6,1,5,9,7,8};
int arr2[]={1,2,3,4,5,6,7};
int len=7;
cout<<find3(arr,len)<<endl;
cout<<find3(arr2,len);
return 0;
}
結果:
解法4:
分割槽,遞迴 :
問題可轉化為:n個正數的陣列A,如果存在小於n的數不在陣列中,必然存在大於n的數在陣列中,否則陣列排列恰好為1到n
舉例判斷邊界(結束條件):
#include<iostream>
#include<algorithm>
using namespace std;
int selectK(int A[],int p,int r,int k);
/*
改進2:分割槽,遞迴
問題可轉化為:n個正數的陣列A,如果存在小於n的數不在陣列中,必然存在大於n的數在陣列中,否則陣列排列恰好為1到n
*/
int find4(int arr[],int l,int r){
if(l>r){
return l+1;
}
int midIndex=l+((r-l)>>1);//中間下標
int q=selectK(arr,l,r,midIndex-l+1);//實際在中間位置的值
int t=midIndex+1;//期望值
if(q==t){//左側緊密
return find4(arr,midIndex+1,r);
}
else{//左側稀疏
return find4(arr,l,midIndex-1);
}
}
int main(){
int arr[]={3,6,1,5,9,7,8};
int len=7;
cout<<find4(arr,0,6);
return 0;
}
//三點中值法
int partition(int A[],int p,int r){
//優化: 在p、r、mid之間,選一箇中間值作為主元
int midIndex=p+((r-p)>>1); //中間下標
int midValueIndex=-1; //中值的下標
if(A[p]<=A[midIndex]&&A[p]>=A[r]){
midValueIndex=p;
}
else if(A[r]<=A[midIndex]&&A[r]>=A[p]){
midValueIndex=r;
}
else{
midValueIndex=midIndex;
}
swap(A[p],A[midValueIndex]);
int pivot=A[p];
int left=p+1;//掃描指標
int right=r; //右側指標
while(left<=right){
//left不停往右走,直到遇到大於主元的元素
while(A[left]<=pivot) left++; //迴圈退出時,left一定是指向第一個大於主元的位置
while(A[right]>pivot) right--; //迴圈退出時,right一定是指向最後一個小於等於主元的位置
if(left<right){
swap(A[right],A[left]);
}
}
//while退出時,兩者交錯,且right指向的是最後一個小於等於主元的位置,也就是主元應該待的位置
swap(A[p],A[right]);
return right; //返回主元在交換完成後的下標
}
int selectK(int A[],int p,int r,int k){
int q=partition(A,p,r); //主元下標
int qK=q-p+1; //主元是第幾個元素(排好序後)
if(qK==k){
return A[q];
}
else if(qK>k){
return selectK(A,p,q-1,k);
}
else{
return selectK(A,q+1,r,k-qK);
}
}
結果:
相關文章
- 第三章:查詢與排序(下)----------- 3.20桶排序排序
- 第三章:查詢與排序(下)----------- 3.21基數排序排序
- 第三章:查詢與排序(下)----------- 3.19 計數排序排序
- 第三章:查詢與排序(下)----------- 3.28 特殊排序(利用sort函式)排序函式
- mysql查詢表中最小可用id值MySql
- 第三章 :查詢與排序-------3.6快排在工程實踐中的優化排序優化
- 第三章:查詢與排序(下)----------- 3.14 逆序對個數排序
- 第三章:查詢與排序(下)----------- 3.16堆的概念及堆排序思路排序
- 高效查詢ECS可用資源的實踐
- 第三章:查詢與排序(下)----------- 3.15基礎學習_樹、二叉樹、堆排序排序二叉樹
- 第三章:查詢與排序(下)----------- 3.27 用計數排序解決員工年齡問題排序
- 查詢與排序02,折半查詢排序
- 第三章:查詢與排序(下)----------- 3.22 總結:10種排序演算法的對比分析排序演算法
- 第三章:查詢與排序(下)----------- 3.23 相關題解:排序陣列中找和的因子排序陣列
- 第三章 :查詢與排序-------3.2你需要掌握的快速排序演算法排序演算法
- 第三章:查詢與排序(下)----------- 3.11 趣味擴充_尋找發帖水王排序
- 第三章:查詢與排序(下)----------- 3.29 題解:判斷陣列的包含問題排序陣列
- 查詢與排序05,氣泡排序排序
- 查詢與排序04,插入排序排序
- 查詢與排序03,選擇排序排序
- 第三章 :查詢與排序(下)-------3.1分治法介紹及關鍵點解析排序
- 第二章 :查詢與排序---------遞迴、查詢與排序補充排序遞迴
- 第三章:查詢與排序(下)----------- 3.10 實戰解題_哪個數字超過了一半?排序
- 第三章 :查詢與排序-------3.7分治模式的完美詮釋_歸併排序排序模式
- 第三章:查詢與排序(下)----------- 3.25 知其然知其所以然:小頂堆與topK的具體程式碼實現排序TopK
- 第三章:查詢與排序(下)----------- 3.9 最快效率求出亂序陣列中第k小的數排序陣列
- 第三章 :查詢與排序-------3.5快排之三指標分割槽法排序指標
- 第二章 :查詢與排序-------希爾排序排序
- mysql多層元資訊與查詢實踐MySql
- 第三章 :查詢與排序-------3.4快排之雙向掃描分割槽法排序
- 實踐007-elasticsearch查詢之2-Request Body與DSL查詢Elasticsearch
- HBase可用性分析與高可用實踐
- 第三章:查詢與排序(下)------------- 3.8題解_調整陣列順序-奇數在左偶數在右排序陣列
- 排序和查詢排序
- 最小可用Id的命令式解法
- select查詢之二:分組與排序排序
- 一種通用查詢語言的定義與實踐
- SQL Cookbook—查詢、排序SQL排序