第一题
分析:整数序列 A中,如果有m个数相等,m>n/2,则这个数就是主元。
解一
1)找出数组里面的数量最多的数,看他是不是数量大于数组长度的一半。 用map来记录数组元素的出现次数。
最后判断 最多的元素个数是否大于n/2
2)代码
#include<iostream>
#include "map"
using namespace std;
int findMainElement(int a[], int n);
int main() {
int a[] = {1, 2, 3, 2, 2, 4, 2, 3};
int b[] = {1, 2, 3, 2, 2, 4, 2};
cout << findMainElement(a, 8) << endl;
cout << findMainElement(b, 7) << endl;
}
int findMainElement(int a[], int n) {
int now_most = a[0];
int now_most_count = 1;
map<int, int> count_map;
for (int i = 0; i < n; ++i) {
int now_count = 0;
if (count_map.count(a[i]) == 0) {
now_count = 1;
count_map.insert(pair<int, int>(a[i], now_count));
} else {
now_count = count_map.at(a[i]) + 1;
count_map[a[i]] = now_count;
}
if (now_count > now_most_count) {
now_most = a[i];
now_most_count = now_count;
}
}
if (now_most_count > n / 2) {
return now_most;
} else {
return -1;
}
}
输出结果:-1,2
3)时间复杂度:O(n),空间复杂度:O(n)
解二
1)不用map,利用增减count数值,两个循环,可减少空间复杂度
设置两个变量num,count。
count初始为1,将第一个数存到num,遍历数组,下一个数与当前数相同,则count+1,否则count-1。直到count=0,就换成下一个数,直到遍历到最后还一个为止。
判断num是不是主元,遍历统计num出现的次数,如果大于n/2,num为主元,如果小于n/2,则没有主元。
ps:count降到0的时候,说明当前数在已遍历的数组元素中不是主元了,并且在已遍历的数组元素中,其他的也不是,所以就要在后续数组元素中 换成其他的数重新计数。
2)代码
#include<iostream>
using namespace std;
int findMainElement(int a[], int n);
int main() {
int a[] = {1, 2, 3, 2, 2, 4, 2, 3};
int b[] = {1, 2, 3, 2, 2, 4, 2};
cout << findMainElement(a, 8) << endl;
cout << findMainElement(b, 7) << endl;
}
int findMainElement(int a[], int n) {
int num = a[0];
int count = 0;
for (int i = 0; i < n; ++i) {
if (count == 0) {
num = a[i];
count++;
} else {
num == a[i] ? count++ : count--;
}
}
if (count == 0) {
return -1;
} else {
int c = 0;
for (int i = 0; i < n; ++i) {
if (num == a[i]) {
c++;
}
}
if (c > n / 2) {
return num;
} else {
return -1;
}
}
}
输出结果:-1,2
3)时间复杂度:O(n),空间复杂度:O(1)
第二题
分析:既然要求时间上高效,则要用空间换时间
1)如果这个n个数是含1~n的不重复序列,则不含有的最小正整数为n+1
否则,这个最小正整数,就小于n
假设输入一个A数组
我们声明一个B数组,长度为n,且初始化都为0
遍历A,假设A中某个值为m,就让B[m-1]=1,小于等于0,或者大于n都不处理,直到A遍历完为止
再遍历B,第一个值为0的下标为s,则返回s+1,如果全都为1,则返回n+1
2)代码
#include<iostream>
#include "map"
using namespace std;
int findMinPosInt(int a[], int n);
int main() {
int a[] = {1, 2, 9, 2, 2, 4, 2, -2};
int b[] = {1, -1, 3, 2, 2, 7, 2};
cout << findMinPosInt(a, 8) << endl;
cout << findMinPosInt(b, 7) << endl;
}
int findMinPosInt(int a[], int n) {
int b[n];
memset(b, 0, sizeof(int) * n);
for (int i = 0; i < n; ++i) {
if (a[i] > 0 || a[i] <= n) {
b[a[i] - 1] = 1;
}
}
for (int i = 0; i < n; ++i) {
if (b[i] == 0) {
return i + 1;
}
}
return n + 1;
}
3)时间复杂度O(n),空间复杂度:O(n)
第三题
分析:a,b,c三个数组,都是升序的
所以我们只要找到最相近的两个数,并且保证另一个集合里面有在这两个数中间的的数即可
1)
用一个数记录的大小
a、将三个数组 同时遍历
b、找出最小的数,将他所在数组往后遍历,如果D变的更小就更新一下(这一步是为了找更小的D)
c、以此循环,直到三个数都遍历到最后
此时D就记录了最小的结果
2)代码
#include<iostream>
using namespace std;
int findMinTrip(int A[], int n, int B[], int m, int C[], int p);
int main() {
int a[] = {1, 2, 2, 2, 4};
int b[] = {-11, 11, 16, 21,};
int c[] = {-19, 19, 39};
int int_size = sizeof(int);
cout << findMinTrip(a, sizeof(a) / int_size, b, sizeof(b) / int_size, c, sizeof(c) / int_size) << endl;
}
bool min_in_3(int a, int b, int c) {//a 是否是三个数中的最小值
if (a <= b && a <= c) {
return true;
} else {
return false;
}
}
int findMinTrip(int A[], int n, int B[], int m, int C[], int p) {
int i = 0, j = 0, k = 0, D_min = INT_MAX, D;
while (i < n && j < m && k < p && D_min > 0) {
D = abs(A[i] - B[j]) + abs(B[j] - C[k]) + abs(C[k] - A[i]);
if (D < D_min) {
D_min = D;
}
if (min_in_3(A[i], B[j], C[k])) {
i++;
} else if (min_in_3(B[j], C[k], A[i])) {
j++;
} else k++;
}
return D_min;
}
输出结果:30
3)时间复杂度:O(n),O(1)