数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
分析
遍历数组,使用 map 计数,超过一半即返回。有个问题:时间复杂度应该怎么算。
int MoreThanHalfNum_Solution(vector<int> numbers) {
map<int, int> cnt;
for (int i = 0; i < numbers.size(); ++i) {
cnt[numbers[i]]++;
if (cnt[numbers[i]] > numbers.size() / 2) {
return numbers[i];
}
}
return 0;
}
最小的 k 个数
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
分析
此题的做法很多种。
方法一:我的第一直觉就是用 set 。很简单,而且默认是排好序的。当然了,用 STL 都是一种蛮作弊的方法。我也不知道时间复杂度该怎么算 。
代码如下:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> input_k;
if (k > input.size()) {
return input_k;
}
set<int> A;
for (int i = 0; i < input.size(); ++i) {
A.insert(input[i]);
}
int count = 0;
for(set<int>::iterator iter = A.begin(); iter != A.end() && count < k; ++iter) {
input_k.push_back(*iter);
count++;
}
return input_k;
}
方法二:使用排序算法,一般选择快速排序。C++ 中自带 sort() 和 qsort() 函数。就不写了。
方法三:因为只需要得到前 k 个数,而不用对它们进行排序。那么先将数组中的前 k 个数作为最小的.时间复杂度:O(n*k)
注意考虑特殊情况:k == 0
int findMax(vector<int> &A) {
int max = A[0];
int index = 0;
for (int i = 0; i < A.size() - 1; ++i) {
if (max < A[i + 1]) {
max = A[i + 1];
index = i + 1;
}
}
swap(A[A.size() - 1], A[index]);
return max;
}
vector<int> GetLeastNumbers_Solution2(vector<int> input, int k) {
if(k > input.size() || k == 0){
vecotr<int> A;
return A;
}
vector<int> output_k(input.begin(), input.begin() + k);
int max = findMax(output_k);
for (int i = k; i < input.size(); ++i) {
if (input[i] < max) {
output_k[k - 1] = input[i];
max = findMax(output_k);
}
}
return output_k;
}
方法四:与方法三类似,只是使用最大堆,元素有 k 个。这样就不用每次都寻找 k 个元素中的最大的了。最大堆1可用 C++ 自带的 prioprity_queue 实现。时间复杂度:O(n*logk)。
代码如下:
vector<int> GetLeastNumbers_Solution3(vector<int> input, int k) {
vector<int> output_k;
if (k > input.size() || k == 0) {
return output_k;
}
priority_queue<int, vector<int>, less<int>> heap;
for (int i = 0; i < k; ++i) {
heap.push(input[i]);
}
for (int i = k; i < input.size(); ++i) {
if (input[i] < heap.top()) {
heap.pop();
heap.push(input[i]);
}
}
while (!heap.empty()) {
output_k.push_back(heap.top());
heap.pop();
}
return output_k;
}
方法五:
类似于快速排序,只是这里只是找元素,找到第 k 大的元素就可以了。时间为 O(n) + O(n/2) + … + O(1) = O(n) 。
代码如下(不懂为什么超时了):
vector<int> GetLeastNumbers_Solution4(vector<int> input, int k) {
if (k > input.size() || k == 0) {
vector<int> output;
return output;
}
int p = 0;
int r = input.size() - 1;
int key_pos = k;
int key = input[p];
int i, j;
while (1) {
i = p;
j = r;
key = input[p];
while (i < j) {
while (input[j] > key) --j;
while (input[i] < key) ++i;
swap(input[i], input[j]);
}
//input[i - 1] = key;
if (k - 1 > i) {
p = i + 1;
}
else if (k - 1 == i) {
vector<int> output_k(input.begin(), input.begin() + k);
return output_k;
}
else if (k - 1 < i) {
r = i - 1;
}
}
}
本文介绍了如何找出数组中出现次数超过一半的数字,并探讨了几种高效查找数组中小的k个数的方法,包括使用集合、排序算法、最大堆等。

104

被折叠的 条评论
为什么被折叠?



