29 最小的K个数
1 // 2 //题目:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 3 4 //思路一:先找到第K个大的数,如何找到任意第K大的数? 5 //首先利用快排思想,先随机的选取一个枢轴,然后进行快速排序分成2部分(左边都小于,后面都大于),最后得到其下标。 6 //然后利用递归思想,将左边快速排序,将右边快速排序 7 //--------Partiton思想时间复杂度O(n)-------------- 8 class Solution 9 { 10 public: 11 void swap(vector<int> &array, int start, int end) 12 { 13 int tmp = array[start]; 14 array[start] = array[end]; 15 array[end] = tmp; 16 } 17 int Partition(vector<int> &input, int start, int end) 18 { 19 20 int pv = input[start]; 21 //int tmp; 22 while(start < end) 23 { 24 while ((start < end) && pv < input[end]) 25 { 26 end--; 27 } 28 //tmp = input[start]; 29 //input[start] = input[end]; 30 //input[end] = tmp; 31 swap(input, start, end); 32 while ((start < end) && pv >= input[start]) 33 { 34 start++; 35 } 36 //tmp = input[start]; 37 //input[start] = input[end]; 38 //input[end] = tmp; 39 swap(input, start, end); 40 } 41 return start; 42 } 43 public: 44 vector<int> GetLeastNumbers_Solution(vector<int> input, int k) 45 { 46 int len = input.size(); 47 if (len <= 0 || k <=0 ||input.size() < k ) 48 { 49 return {}; 50 } 51 int start = 0; 52 int end = len-1; 53 int index = Partition(input,start, end); 54 while(index != k-1) 55 { 56 if (index > k-1) 57 { 58 end = index -1; 59 index = Partition(input,start, end); 60 } 61 else 62 { 63 start = index+1; 64 index = Partition(input,start, end); 65 } 66 } 67 vector<int> tmpVec(input.begin(), input.begin() + k); 68 return tmpVec; 69 } 70 71 }; 72 //调试程序中出现的问题: 73 //首先做交换函数定义的时候,参数要是引用类型void swap(vector<int> &array, int start, int end) 74 //第二个,就是快排的时候,做交换swap(input, start, end); 75 //第三个,快排的枢轴选取为int pv = input[start]; 76 //第四个,数组中任意第K大的数字 77 // 找任意的第K大的数字,就要想到快排。 78 // int index = Partition(array[], n, int start, int end); 79 // while(index != K-1) 80 // { 81 // if(index > k-1) 82 // { 83 // end = index-1; 84 // Partition(array[],n, start, end); 85 // } 86 // else 87 // { 88 // start = index+1; 89 // Partition(array[], n, start, end); 90 // } 91 // } 92 // 第五个,使用vector容器的时候,添加元素的时候,不要总是使用push_back(); 93 // 还可以使用迭代器, 94 // 例如:vector<int> tmpVec(input.begin(), input.begin() + k); 95 96 //------------采用时间复杂度O(nlogk)的算法,特别适合处理海量数据 97 //思路:我们可以创建一个大小为K的数据容器来存储最小的K个数字,接下来我们每次从输入的N个整数中读入一个数。
如果容器中已有数字少于K个,则直接把这次读入的整数放入容器中;如果容器中已有K个数字了,就是容器已满,
此时我们不能再插入新的数字而只能替换已有的数字。找出这已有K个数字中的最大值,然后拿这次带插入的整数和最大值进行比较。
如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还要大,
那么这个数不可能是最小的K个整数之一,于是就抛弃这个整数。 98 //操作如下: 99 //1、在K个整数中找到最大数; 100 //2、有可能在这个容器中删除最大数; 101 //3、有可能要插入一个新的数字。 102 //如果用一个二叉树来实现这个数据容器,那么我们能在O(logk)时间内实现操作。因此对于n个输入数字而言,总的时间效率就是O(nlogk) 103 104 //常识:想到二叉树来解决问题,就要想到用什么二叉树为好? 105 //如该题就是每次都需要找到K个整数中最大的数字,很容易想到最大堆。在最大堆中,根节点的值总是大于它的子树中任意结点的值。 106 //最大堆常识--在O(1)得到已有的K个数字中的最大值,但需要O(logk)时间完成删除和插入操作。 107 108 //也可以用红黑树来代替最大堆来实现容器。红黑树通过把结点分为红黑两种颜色并根据一些规则确保树在一定程度上是平衡的,从而保证在红黑书中查找、删除和插入都只需要O(logk)时间。 109 //------------------红黑树:multiset集合利用仿函数改变排序顺序时间复杂度O(nlogk)----- 110 class Solution 111 { 112 typedef multiset<int, greater<int>> intset; 113 typedef multiset<int ,greater<int>>::iterator setIterator; 114 public: 115 vector<int> GetLeastNumbers_Solution(vector<int> input, int k) 116 { 117 if (input.size() <= 0 || k<=0 || k > input.size()) 118 { 119 return {}; 120 } 121 intset hasKDigits;//定义红黑树来解决容器 122 hasKDigits.clear();//用之前先清空操作 123 vector<int>::const_iterator iter = input.begin(); 124 125 while(iter != input.end()) 126 { 127 if ((hasKDigits.size())<k) 128 { 129 hasKDigits.insert(*iter); 130 } 131 else 132 { 133 //第一个元素是最大值 134 setIterator iterGreatest = hasKDigits.begin(); 135 if (*iter < *(hasKDigits.begin())) 136 { 137 hasKDigits.erase(iterGreatest); 138 hasKDigits.insert(*iter); 139 } 140 } 141 ++iter; 142 } 143 return vector<int>(hasKDigits.begin(), hasKDigits.end()); 144 } 145 }; 146 //总结调试信息: 147 //第一个,k>input.size()必须要写出来 148 //第二个,在条件判断语句中,不要 149 // iterEnd = iter.end(); 150 // if(iter != iterEnd);而应该写成if(iter!=iter.end()) 151 // 原因,是因为你在循环条件语句中做迭代器操作,会使迭代器失效。 152 //第三个,if (*iter < *(hasKDigits.begin())) 尽量不要写if (*iter < *(iterGreatest)) 153 //原因,在set容器中被删除的迭代器会失效。即不能使用erase(iter++),而应该使用 154 //for( iter = c.begin(); iter != c.end(); ) 155 //iter = c.erase(iter); 156 //第四个,return {};可以写成return vector<int>(); 157 //第五个,返回匿名容器 return vector<int>(hasKDigits.begin(), hasKDigits.end()); 158 159 160 161 //------------------最大堆时间复杂度O(nlogk)----- 162 class Solution { 163 public: 164 vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { 165 int len=input.size(); 166 if(len <= 0 || k> len || k <= 0) 167 return vector <int >(); 168 169 vector<int> res(input.begin(),input.begin()+k); 170 //建堆 171 make_heap(res.begin(),res.end()); 172 173 for(int i=k;i<len;i++) 174 { 175 if(input[i]<res[0]) 176 { 177 //先pop,然后在容器中删除 178 pop_heap(res.begin(),res.end()); 179 res.pop_back(); 180 //先在容器中加入,再push 181 res.push_back(input[i]); 182 push_heap(res.begin(),res.end()); 183 } 184 } 185 //使其从小到大输出 186 sort_heap(res.begin(),res.end()); 187 188 return res; 189 190 } 191 }; 192 //总结说明 193 //使用STL中的最大堆时 194 // 建立堆,首先要堆原始数据进行备份,通过备份数据建立堆 195 // vector<int> res(input.begin(),input.begin()+k); 196 // //建最大堆 197 // make_heap(res.begin(),res.end()); 198 // //在堆中删除数据--要先调用pop_heap,再在容器中删除数据 199 // pop_heap(res.begin(),res.end()); 200 // //在堆中添加数据-要先在容器中加入数据,再调用push_heap () 201 // push_heap (_First, _Last) 202 // //堆排序--排序之后就不再是一个合法的heap了 203 // sort_heap(_First, _Last) 204 205 //--------------全排序时间复杂度O(nlogn)-------- 206 class Solution { 207 public: 208 vector<int> GetLeastNumbers_Solution(vector<int> input, int k) 209 { 210 vector<int> res; 211 if(input.empty()||k>input.size()) 212 return res; 213 214 sort(input.begin(),input.end()); 215 216 for(int i=0;i<k;i++) 217 res.push_back(input[i]); 218 219 return res; 220 221 } 222 };
在代码的世界尽情的翱翔吧!