算法导论上机题一
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
1. Implement exercise 2.3-7.
請(qǐng)給出一個(gè)運(yùn)行時(shí)間為θ(nlgn)的算法,使之能在給定一個(gè)由n個(gè)整數(shù)構(gòu)成的集合S和另一個(gè)整數(shù)x時(shí),判斷出S中是否存在有兩個(gè)其和等于x的元素。
問(wèn)題分析:
?????? 可以先將此問(wèn)題分為兩個(gè)部分:集合S排序和查找,查找可以用時(shí)間復(fù)雜度為θ(lgn) 的折半查找,因此,若要滿(mǎn)足題目要求,排序算法的時(shí)間復(fù)雜度不可以超過(guò)θ(nlgn)。
?????? 時(shí)間復(fù)雜度為θ(nlgn)的算法有快速排序、堆排序和歸并排序,但快速排序在最壞情況下時(shí)間復(fù)雜度為θ(n*n),堆排序適用于大量數(shù)據(jù)的情況,在數(shù)據(jù)量較小的情況下堆排序并不提倡使用,因此采用歸并排序算法。盡管它需要額外的空間,但好在題目沒(méi)有要求。
?????? 具體實(shí)現(xiàn)方法如下,首先將S排成有序集合,然后對(duì)S中的每一個(gè)元素si,判斷x-si是否在集合S中(折半查找),如此即可滿(mǎn)足題意。
源碼:
#include<iostream> using namespace std;void M(int* A,int l,int q,int r){int n1=q-l+1;int n2=r-q;int L[n1+1],R[n2+1];int i,j;for(i=0;i<n1;i++){L[i]=A[l+i];}for(j=0;j<n2;j++){R[j]=A[q+j+1];}L[n1]=1000;R[n2]=1000;i=0;j=0;for(int k=l;k<=r;k++){if(L[i]<=R[j]){A[k]=L[i];i++;}else{A[k]=R[j];j++;}} }void MSORT(int* A,int l,int r){if(l<r){int q=(l+r)/2;MSORT(A,l,q);MSORT(A,q+1,r);M(A,l,q,r);} }bool binarysearch(int* A,int y,int min,int max){int mid;while(min<=max){mid=(min+max)/2;if(A[mid]==y){return true;}if(A[mid]>y){max=mid-1;}else{min=mid+1;}}return false; }bool checksum(int* A,int x){int n=16;for(int i=0;i<n;i++){if(A[i]>=0&&binarysearch(A,x-A[i],0,15)){return true;}}return false; }int main(){int A[16],x;cout<<"Before sorting:"<<endl;for(int i=0;i<16;i++){A[i]=rand()%100;cout<<A[i]<<" ";}cout<<endl;cout<<"Input x:";cin>>x;MSORT(A,0,15);cout<<"After sorting:"<<endl;for(int i=0;i<16;i++){cout<<A[i]<<" ";}cout<<endl;if(checksum(A,x)){cout<<"Find it!"<<endl;}else{cout<<"Do not exist!"<<endl;}system("pause");return 0; }2. Implement priority queue.
問(wèn)題分析:
?????? 以最大優(yōu)先級(jí)隊(duì)列為例:構(gòu)建優(yōu)先級(jí)隊(duì)列即為在一串亂序數(shù)字中,第k次將第k大的數(shù)字找出來(lái),因此不進(jìn)行排序,直接構(gòu)造最大堆,然后將堆的根依次extract,即為最大優(yōu)先級(jí)隊(duì)列。
?????? 因?yàn)椴粚?duì)構(gòu)建的最大堆進(jìn)行排序,僅僅是extract根節(jié)點(diǎn),所以建堆階段時(shí)間復(fù)雜度要小于堆排序,而之后的heap_extract_max操作運(yùn)行時(shí)間為ο(lgn),對(duì)n個(gè)元素,又堆中節(jié)點(diǎn)是逐漸減少,故時(shí)間復(fù)雜度小于ο(nlgn)。
源碼:
#include<iostream> using namespace std;int length=16; int heap_size;int parent(int i){return (i-1)/2; }int left(int i){return 2*i+1; }int right(int i){return 2*i+2; }void exchange(int& a,int& b){int t;t=a;a=b;b=t; }void max_heapify(int* A,int i){int l=left(i);int r=right(i);int largest;if(l<heap_size&&A[l]>A[i])largest=l;elselargest=i;if(r<heap_size&&A[r]>A[largest]){largest=r;}if(largest!=i){exchange(A[i],A[largest]);max_heapify(A,largest);} }void build_max_heap(int* A){heap_size=length; for(int i=length/2-1;i>=0;i--){max_heapify(A,i);} }/*int heap_maximum(int* A){return A[0]; }*/int heap_extract_max(int* A){if(heap_size<1){exit(-1);}int max=A[0];A[0]=A[heap_size-1];heap_size--;max_heapify(A,0);return max; }/*void heap_increase_key(int* A,int i, int key){if(key<A[i]){exit(-2);}A[i]=key;while(i>0&&A[parent(i)]<A[i]){exchange(A[i],A[parent(i)]);i=parent(i);} }*//*void max_heap_insert(int* A,int key){A[heap_size]=-1000;heap_increase_key(A,heap_size,key); }*/int main(){int A[20];int n;cout<<"Before Heapify;"<<endl;for(int i=0;i<length;i++){A[i]=rand()%100;cout<<A[i]<<" ";}cout<<endl;build_max_heap(A);cout<<"After Heapify:"<<endl; for(int i=0;i<length;i++){cout<<A[i]<<" ";}cout<<endl;/*cout<<"Input the number you want to insert:"<<endl;cin>>n;max_heap_insert(A,n);for(int i=0;i<length+1;i++){cout<<A[i]<<" ";}cout<<endl;*/cout<<"The priority queue is:"<<endl;for(int i=0;i<length;i++){cout<<heap_extract_max(A)<<" ";}cout<<endl;system("pause");return 0; }3. Implement Quicksort and answer the following questions.
(1) How many comparisons will Quicksort do on a list of n elements that all have the same value?
(2) What are the maximum and minimum number of comparisons will Quicksort do on a list of n elements, give an instance for maximum and minimum case respectively.
問(wèn)題分析:
?????? 此題目?jī)H要求一個(gè)簡(jiǎn)單的快速排序?qū)崿F(xiàn),附帶兩個(gè)問(wèn)題,在對(duì)快速排序理解的基礎(chǔ)上并不難完成。
?????? 作為對(duì)冒泡排序的一種改進(jìn),快速排序成功的將平均時(shí)間復(fù)雜度降為Ο(nlog n),每一趟排序它用分治法的策略把一個(gè)序列分為兩個(gè)子序列,我們學(xué)習(xí)的快速排序是一個(gè)原地分割的版本,也就降低了空間復(fù)雜度。
源碼:
#include<iostream> using namespace std;int n=0; void exchange(int& a,int& b){int t;t=a;a=b;b=t; }int PARTITION(int* A,int l,int r){int x=A[r];int i=l-1;for(int j=l;j<=r-1;j++){if(A[j]<=x){n++;i++;exchange(A[i],A[j]);}}exchange(A[i+1],A[r]);return i+1; }void QUICKSORT(int* A,int l,int r){if(l<r){int q=PARTITION(A,l,r);QUICKSORT(A,l,q-1);QUICKSORT(A,q+1,r);} }int main(){ // int A[7]={1,3,2,5,7,6,4};//bestint A[7]={1,2,3,4,5,6,7};//worstcout<<"Before Sorting;"<<endl;for(int i=0;i<7;i++){ // A[i]=11;cout<<A[i]<<" ";}cout<<endl;QUICKSORT(A,0,6);cout<<"After Sorting:"<<endl; for(int i=0;i<7;i++){cout<<A[i]<<" ";}cout<<endl;cout<<"Count:"<<n<<endl;system("pause");return 0; }4. Give a divide and conquer algorithm for the following problem: you are given two sorted lists of size m and n, and are allowed unit time access to the ith element of each list. Give an O(lg m + lgn) time algorithm for computing the kth largest element in the union of the two lists. (For simplicity, you can assume that the elements of the two lists are distinct).
問(wèn)題分析:
?????? 假設(shè)兩個(gè)有序的序列為從大到小排列。問(wèn)題要求時(shí)間復(fù)雜度為O(lg m + lgn),并且采用分治的方式,因此可將兩個(gè)序列(命名為A和B)分別從中間分開(kāi),子序列長(zhǎng)度為m/2(設(shè)x)、n/2(設(shè)y)。這樣A[x]和B[y]就是A和B中間的元素。
?????? 設(shè)A[x]>B[y](同理可得A[x]<B[y]的情況),這樣合并后A[x]之前的元素必然在B[y]之前,即B[y]之前至少有x+y+1個(gè)元素。若k<x+y+1,則可排除B序列的后半部分元素,也就是將B排除了一半。
?????? A[x]之后有m-x-1個(gè)元素,B[y]之后有n-y-1個(gè)元素,由于A[x]>B[y],則A[x]之后有至少(m-x-1)+(n-y-1)+1=(m+n)-(x+y+1)個(gè)元素。這樣若k>x+y+1,則可將A[x]之前的元素排除,也就是將A排除了一半。
?????? 每一次比較必將A或者B排除一半,根據(jù)分治方法,不難判斷出算法的時(shí)間復(fù)雜度為O(lg m + lgn)。
源碼:
#include<iostream> using namespace std;int A[8]={0,3,6,7,11,14,16,23}; int B[13]={1,4,5,10,15,19,24,26,27,28,31,35,40};int searchk(int al,int ar,int bl,int br,int k){int am=(al+ar)/2;int bm=(bl+br)/2;if(al>ar) return B[bl+k-1]; if(bl>br) return A[al+k-1];if (A[am] <= B[bm]) { if (k <= (am - al) + (bm - bl) + 1) { return searchk(al, ar, bl, bm-1, k); } else { return searchk(am+1, ar, bl, br, k-(am-al)-1); } } else { if (k <= (am - al) + (bm - bl) + 1) { return searchk(al, am-1, bl, br, k); } else { return searchk(al, ar, bm+1, br, k-(bm-bl)-1); } } return -1; }int main(){int k;cout<<"INPUT K:";cin>>k;int n=searchk(0,7,0,12,22-k);cout<<"The "<<k<<"th largest element is "<<n<<endl;return 0; }轉(zhuǎn)載于:https://my.oschina.net/zhangjinhui/blog/60338
總結(jié)
- 上一篇: 线程的各种锁
- 下一篇: 关于Static控件背景透明时文本覆盖重