剑指offer——优化时间和空间效率(第五章)
面试题29:数组中出线次数超过一半的数字
数组中有一个数字出线的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
思路1:
对于有序的数组,出线次数超过一半的数字肯定会出现在数组中间的位置。
对数组进行排列,然后直接输出排列后数组中间位置的数字
注意:排序算法的使用——快速排序!
思路2:
这个数字出线的次数比其他所有数字出线的次数和要多。
遍历数组,保存两个值,一个数组中的一个数字,一个是次数。
次数:初始为1。
数字:初始为第一个值。
当下一个数字与其前一个数字相同,则次数+1;否则次数-1;
当次数为0时,下一个数字为保存数字。
这样,最后保存的数字一定为所求数字~(它的次数大于其它所有数字的和)。
1 #include <iostream> 2 using namespace std; 3 void QuickSort(int* arr,int left,int right); 4 int Partition(int* arr,int left,int right); 5 int MoreThanHalfNum1(int* arr,int len); 6 int MoreThanHalfNum2(int* arr,int len); 7 void Change(int &a,int &b) 8 { 9 int temp=a; 10 a=b; 11 b=temp; 12 } 13 int main() 14 { 15 const int mSize=20; 16 int a[mSize]={1,2,3,2,2,2,5,4,2}; 17 int len=9; 18 // for(int i=0;i<len;i++) 19 // cout<<a[i]<<" "; 20 cout<<MoreThanHalfNum2(a,len); 21 return 0; 22 } 23 int MoreThanHalfNum1(int* arr,int len) 24 { 25 if(!arr||len<=0) 26 return 0; 27 QuickSort(arr,0,len-1); 28 int mid=(len-1)/2; 29 return arr[mid]; 30 } 31 void QuickSort(int* arr,int left,int right) 32 { 33 int index; 34 if(left<right) 35 { 36 index=Partition(arr,left,right); 37 QuickSort(arr,left,index-1); 38 QuickSort(arr,index+1,right); 39 } 40 } 41 int Partition(int* arr,int left,int right) 42 { 43 int i=left-1; 44 for(int j=left;j<right;j++) 45 { 46 if(arr[j]<=arr[right]) 47 { 48 i++; 49 Change(arr[i],arr[j]); 50 } 51 } 52 Change(arr[i+1],arr[right]); 53 return i+1; 54 } 55 int MoreThanHalfNum2(int* arr,int len) 56 { 57 if(!arr||len<=0) 58 return 0; 59 int result=arr[0]; 60 int time=1; 61 for(int i=1;i<len;i++) 62 { 63 if(time==0) 64 { 65 result=arr[i]; 66 time=1; 67 } 68 else if(arr[i]==result) 69 time++; 70 else time--; 71 } 72 return result; 73 }
面试题30:最小的k个数
输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8这8个数字,则最小的4和数是1、2、3、4
思路1:
排序,选择前k个数,时间复杂度为O(nlogn),面试官可能不满意
并且该方案改变了原来数组的结构(当然这不是问题)。
思路2:
与29道思路二类似:
遍历一边数组即可:定位arr[k],遍历数组,所有比arr[k]小的数放在arr[k]左边,比它大的数放在其右边。这不类似于快速排序里面那个Partition嘛~
具体实现:(基于Partition)
我们知道,Partition得到的是一个值,小于这个值的都在其左边,大于这个值的都在其右边。
而我们的目标是:小于arr[k-1]的都在其左边,而大于arr[k-1]的都在其右边,因此arr[0]-arr[k-1]就是所求的k个数
这样的话,问题就简单了,只要Partition的返回值为k-1就行了。
因此:如果Partition的返回值<k-1,则在其右侧继续进行Partition;而Partition的返回值>k-1,则在其左侧继续Partition
1 #include <iostream> 2 using namespace std; 3 void Change(int &a,int &b) 4 { 5 int temp; 6 temp=a; 7 a=b; 8 b=temp; 9 } 10 /// 方案1:先排序,直接找出排序后的前k个 11 void GetLeastNumbers1(int* arr,int len,int k); 12 int Partition(int* arr,int left,int right); 13 void QuickSort(int* arr,int left,int right); 14 15 ///方案2:基于Partition的方法 16 void GetLeastNumbers2(int* arr,int len,int k); 17 18 19 int main() 20 { 21 int arr[]={4,5,1,6,2,7,3,8}; 22 int k=4; 23 int len=sizeof(arr)/sizeof(arr[0]); 24 // GetLeastNumbers1(arr,len,k); 25 GetLeastNumbers2(arr,len,k); 26 return 0; 27 } 28 29 ///1: 30 int Partition(int* arr,int left,int right) 31 { 32 int i=left-1; 33 for(int j=left;j<right;j++) 34 { 35 if(arr[j]<=arr[right]) 36 { 37 i++; 38 Change(arr[i],arr[j]); 39 } 40 } 41 Change(arr[i+1],arr[right]); 42 return i+1; 43 } 44 void QuickSort(int* arr,int left,int right) 45 { 46 if(!arr||left>right) return; 47 if(left<right) 48 { 49 int index=Partition(arr,left,right); 50 QuickSort(arr,left,index-1); 51 QuickSort(arr,index+1,right); 52 } 53 } 54 void GetLeastNumbers1(int* arr,int len,int k) 55 { 56 if(!arr||len<0||len<k) return; 57 QuickSort(arr,0,len-1); 58 for(int i=0;i<k;i++) 59 cout<<arr[i]<<" "; 60 } 61 62 ///2: 63 void GetLeastNumbers2(int* arr,int len,int k) 64 { 65 if(!arr||len<0||len<k) return; 66 int left=0,right=len-1; 67 int index=Partition(arr,left,right); 68 while(index!=k-1) 69 { 70 if(index<k-1) 71 { 72 left=index+1; 73 index=Partition(arr,left,right); 74 } 75 else 76 { 77 right=index-1; 78 index=Partition(arr,left,right); 79 } 80 } 81 for(int i=0;i<k;i++) 82 cout<<arr[i]<<" "; 83 }
1 ///3: 2 void GetLeastNumbers3(vector<int> arr,int k) 3 { 4 vector<int>::iterator iter1=arr.begin(); 5 multiset<int,greater<int> > leastNumbers; 6 multiset<int,greater<int> >::iterator iter2; 7 for(;iter1!=arr.end();iter1++) 8 { 9 if((leastNumbers.size())<k) 10 leastNumbers.insert(*iter1); 11 else 12 { 13 multiset<int,greater<int> >::iterator temp=leastNumbers.begin(); 14 if(*iter1<*(leastNumbers.begin())) 15 { 16 leastNumbers.erase(temp);//删除顶端元素,最大堆中顶端元素就是最大的元素 17 leastNumbers.insert(*iter1); 18 } 19 } 20 } 21 for(iter2=leastNumbers.begin();iter2!=leastNumbers.end();iter2++) 22 cout<<*iter2<<" "; 23 cout<<endl; 24 }
posted on 2015-07-08 10:40 VisualTracker 阅读(105) 评论(0) 编辑 收藏 举报