2-5 集合减法 分数 6
作者 朱允刚
单位 吉林大学
给定两个非空集合A和B,集合的元素为30000以内的正整数,编写程序求A-B。
输入格式: 输入为三行。第1行为两个整数n和m,分别为集合A和B包含的元素个数,1≤n, m ≤10000。第2行表示集合A,为n个空格间隔的正整数,每个正整数不超过30000。第3行表示集合B,为m个空格间隔的正整数,每个正整数不超过30000。
输出格式: 输出为一行整数,表示A-B,每个整数后一个空格,各元素按递增顺序输出。若A-B为空集,则输出0,0后无空格。
输入样例:
输出样例:
我的超时代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <iostream> using namespace std;typedef struct { int *data; int length; } sqList; void initList (sqList &L, int n) { L.data = new int [n]; L.length = 0 ; } int findELem (sqList L, int x) { for (int i = 0 ; i < L.length; ++i) { if (L.data[i] == x) { return i; } } return -1 ; } int main () { int n, m; cin >> n >> m; sqList L1; sqList L2; initList (L1, n); initList (L2, m); for (int i = 0 ; i < n; ++i) { cin >> L1. data[i]; L1.l ength++; } for (int i = 0 ; i < m; ++i) { cin >> L2. data[i]; L2.l ength++; } for (int i = 0 ; i < m; ++i) { int isFind = findELem (L1, L2. data[i]); if (isFind != -1 ) { for (int j = isFind; j < L1.l ength-1 ; j++) { L1. data[j] = L1. data[j+1 ]; } L1.l ength--; } } if (L1.l ength != 0 ){ for (int i = 0 ; i < L1.l ength; ++i) { cout << L1. data[i] << " " ; } } else { cout << "0" ; } }
1. 查找操作 (findELem)
操作: 在顺序表 L1 (集合 A) 中查找元素 L2.data[i]。
时间复杂度: findELem 函数使用线性遍历。在最坏情况下(元素在表尾或不存在),它需要检查 N 个元素。
结论: 查找操作的时间复杂度为 O(N) ,其中 N 是集合 A 的当前长度。
2. 删除操作(移动元素)
操作: 当元素找到后,将其从顺序表 L1 中删除。由于顺序表是连续存储的,删除一个元素需要将该元素之后的所有元素向前移动一位。
时间复杂度: 在最坏情况下(删除第一个元素),需要移动 N−1 个元素。
结论: 删除操作的时间复杂度为 O(N)。
3. 总体时间复杂度
外层循环遍历集合 B,执行 M 次。
内层循环中,每次迭代都执行一次 O(N) 的查找和一次最坏 O(N) 的删除。
因此,整个集合减法操作的总时间复杂度 为:
总时间≈M×(查找时间+删除时间)=M×(O(N)+O(N))=O(M×N)
4. 为什么会超时 根据题目约束,集合 A 的元素个数 N 和集合 B 的元素个数 M 都可达 10000。
最坏情况下,操作次数将达到:
10000×10000=108 次
解决 为了解决超时问题,我将查找操作从 O(N) 优化到了 O(1)(常数时间)。
我引入了一个布尔数组 exists (大小为 30001)。
这个数组相当于一个高效的查找表 。
通过检查 exists[x] 的值,我们可以在瞬间 判断元素 x 是否在集合 B 中,这完全取代了 findELem 的作用。
正确代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 #include <iostream> using namespace std;const int MAX_ELEM = 30000 ;bool exists[MAX_ELEM + 1 ];typedef struct { int *data; int length; } sqList; void initList (sqList &L, int n) { L.data = new int [n]; L.length = 0 ; } void pushBack (sqList &L, int x) { L.data[L.length] = x; L.length++; } int main () { int n, m; cin >> n >> m; sqList A; initList (A, n); for (int i = 0 ; i < n; ++i) { cin >> A.data[i]; A.length++; } for (int i = 1 ; i <= MAX_ELEM; ++i) { exists[i] = false ; } for (int i = 0 ; i < m; ++i) { int b_val; cin >> b_val; exists[b_val] = true ; } sqList resultList; initList (resultList, n); for (int i = 0 ; i < A.length; ++i) { int val = A.data[i]; if (!exists[val]) { pushBack (resultList, val); } } if (resultList.length == 0 ){ cout << "0" ; } else { for (int i = 0 ; i < resultList.length; ++i) { cout << resultList.data[i] << " " ; } } cout << "\n" ; }