剑指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 }
View Code

 

面试题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 }
View Code

 

 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 }
View Code

 

posted on 2015-07-08 10:40  VisualTracker  阅读(105)  评论(0编辑  收藏  举报