第三章 栈
p57 等价类划分问题 - 邻接表的DFS
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 void equiv (int n, int r) { int a, b, visit[n+1 ] = {0 }; stack<int > stack; AGragh *g = new AGragh (); G->n = n, G->e = r; for (int i = 1 ; i <= n; i++) { g->adjList[i].firstarc->next = NULL ; } for (int i = 1 ; i < r; i++) { scanf ("%d%d" , &a, &b); ListInsert (0 , b, g->adjList[a]); ListInsert (0 , a, g->adjList[b]); } for (int i = 1 ; i < r; i++) { if (visit[i] == 0 ) { stack.push (); while (!stack.empty ()) { int cur = stack.top (); cout<< cur << " " ; ANode *q = g->adjList[cur].firstarc; while (visit[q->adjvex] == 1 && q) q = q->nextarc; if (q == NULL ) stack.pop (); else { visit[q->adjvex] = 1 ; stack.push (q->adjvex); } } printf ("\n" ); } } }
p59 直方图最大面积矩形问题 -
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 int hosto (int n, int p) { int max = 0 ; i = 0 , s; stack<int > stack; while (i<n) { if (stack.empty () && p[stack.top ()] <= p[i]) stack.push (i); i++; else { int temp = stack.top (); stack.pop (); if (stack.empty ()) s = p[temp] * i; else s = p[temp] * (p - stack.top () + 1 ); if (max < s) max = s; } } while (!stack.empty ()) { int temp = stack.top (); stack.pop (); if (stack.empty ()) s = p[temp] * i; else s = p[temp] * (p - stack.top () + 1 ); if (max < s) max = s; } return max; }
第四章 队列
p70 电路布线问题 BFS + 回溯
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 int search (vector<int > a, vector<int > b, vector<vector<int >> pos) { int dx[4 ] = {-1 , 0 , 1 , 0 }, dy[4 ] = {0 , 1 , 0 , -1 }; queue<vector<int >> q; if (a[0 ][0 ] == b[0 ][0 ] && a[0 ][1 ] == b[0 ][1 ]) return 0 ; q.push (a); pos[a[0 ][0 ]][a[0 ][1 ]] = 2 ; int step = 2 , size, len; vector<int > m, ans; while (!q.empty ()) { size = q.size (); step += 1 ; m = q.front (); q.pop (); for (int j = 0 ; j < size; j++) { for (int i = 0 ; i < 4 ; i++) { int x = dx[i] + m[0 ][0 ], y = dy[i] + m[0 ][1 ]; if (x>=0 && x<pos.size () && y>=0 && y<pos[i].size () && pos[x][y] == 0 ) { ans[0 ][0 ] = x; ans[0 ][1 ] = y; q.push (ans); pos[x][y] = step; } if (x == b[0 ][0 ] && y == b[0 ][1 ]) { len = pos[x][y] - 2 ; return pos[x][y] - 2 ; } } } } return 0 ; }
p72 窗口查询问题 单调队列(双端)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 vector<int > maxSlidingWindow (vector<int >& nums, int k) { deque<int > q; int left=0 , max; vector<int > ans; if (nums.size ()==0 ) return ans; for (int i = 0 ; i < nums.size (); i++) { while (!q.empty () && nums[q.back ()] <= nums[i]) q.pop_back (); if (!q.empty () && i - q.front () >=k) q.pop_front (); q.push_back (i); max = nums[q.front ()]; if (i>=k-1 ) { ans.push_back (max); } } return ans; }
第五章 排序
各类改进算法
p98 带权中位数 快排 + 分治
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 int main () { int R[m] = ... quickSort (R, 0 , m); int i = 0 ; double c = 0 ; while (i<m && c+R[i]<0.5 ) c+=R[i]; return R[i]; } void quickSort (int R[], int low, int high) { int temp = R[low]; int i = low, j = high; if (low < high) { while (i < j) { while (i<j && R[j]>temp) j--; if (i<j) { R[i] = R[j]; ++i; } while (i<j && R[i]<temp) i++; if (i<j) { R[j] = R[i]; --j; } } R[i] = temp; quickSort (R, low, i-1 ); quickSort (R, i+1 , high); } }
拓展:部分背包问题
问题描述 :
一个窃贼去一家商店偷窃,有n件商品:第 i 件商品价值 vi 元,重 wi 磅(vi、wi都是整数),他的背包最多只能装下 w 磅物品,每个商品他可以选择一部分带走,问他最多能带走多贵的物品?
问题分析:
窃贼可对每件商品选择一部分带走,这不同于0-1背包问题,这里的商品就像是金粉😳
算法分析 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 我们可以对每件商品的价值 —— 每磅的价值 进行排序,然后按价值大小依次往背包里装,这样,时间复杂度为 O (n*logn)。这里,时间复杂度主要是排序,那么,可以不排序吗? 当然OK。就像是上面查找带权中位数的算法,排序只是为了将单价高的商品筛选出来,所以我们并不需要将所有的商品价值进行排序。 采用分治法(divide and conquer),先找出中位数! 找出其中位数,将数组分为 SL[单价大于中位数]、SV[单价等于中位数]、SR[单价小于中位数] 三个集合; 接下来分3 种情况: ①如果 SL 数组中所有商品的重量 ≥ w,则问题在 SL 中递归解决; ②如果 SL + SV ≥ w,则先将 SL 中的物品全部装入包中,然后在 SV 中递归解决; ③如果 SL + SV < w,则将 SL 和 SV 中的物品全部装入背包中,再在 SR 中递归解决。
时间复杂度分析:
1 T (n) ≤ T (n/2 ) + O (n) → T (n) = O (n)
p99 最大递增序列 排序 + 贪心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int maxs (vector<vector<int >> s) { int n = s.size (), m = s[0 ].size (); for (int i = 0 ; i < n; i++) { sort (s[i], 0 , m); } int sum = s[n-1 ][m-1 ], pre = s[n-1 ][m-1 ]; for (int i = n-2 ; i>=0 ; i--) { for (int j=m-1 ; j>=0 ; j--) { if (a[i][j] < pre) { pre = a[i][j]; sum+= pre; break ; } } if (j==-1 ) return 0 ; } return sum; }
第六章 二叉树
p143 信号增强装置 贪心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void Place (btlink x) { int deg; btlink y->left; x->element.D = 0 ; if (y) { deg = y.element->D + y.element->d; if (deg > tol) { y.element->boost = 1 ; x.element->D = y.element->d; } else x.element->D = deg; } y = x->right; if (y) { deg = y.element->D + y.element->d; if (deg > tol) { y.element->boost = 1 ; x.element->D = y.element->d; } if (x->element.D<deg) x.element->D = deg; } }
p145 最长连续递增子序列 像分治
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int maxLengthAc (int arr[], int n, int Len[]) { int max = 1 ; for (int i = 0 ; i<n-1 ; i++) { if (arr[i+1 ] > arr[i]) Len[i+1 ] = Len[i]+1 ; if (Len[i+1 ] > max){ max = Len[i+1 ]; q = i+1 ;} } return max; } int main () { int n; scanf ("%d" , &n); int arr[n], Len[n]; for (int i = 0 ; i < n; i++) { scanf ("%d" , &arr[i]); Len[i] = 1 ; } int max = -1 ; max = maxLengthAc (arr, n, Len); for (int i = q-max+1 ; i<=q; i++) { printf ("%d " , arr[i]); } }
第七章 散列表
p170 元素唯一性问题
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 const int N = 12 ;int n, h[N], a[N];bool find (int x) { int k = x % N; while (a[k]!=-1 && a[k]!=x) { k++; if (k==N) k = 0 ; } return k; } int main () { scanf ("%d" , &n); for (int i = 0 ; i < n; i++) { scanf ("%d" , &h[i]); } memset (a, -1 , sizeof a); for (int i = 0 ; i < n; i++) { int k = find (h[i]); if ( a[k] == h[i]) { cout << "元素重复" << endl; exit (-1 ); } else { a[k] = h[i]; } } cout << "无重复元素" << endl; }
p170 字符串频率统计问题
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 int son[N][26 ], cnt[N], idx;void insert (char *str) { int p = 0 ; for (int i = 0 ; str[i]; i ++ ) { int u = str[i] - 'a' ; if (!son[p][u]) son[p][u] = ++ idx; p = son[p][u]; } cnt[p] ++ ; } int query (char *str) { int p = 0 ; for (int i = 0 ; str[i]; i ++ ) { int u = str[i] - 'a' ; if (!son[p][u]) return 0 ; p = son[p][u]; } return cnt[p]; } int main () { scanf ("%d" , &n); char op[2 ]; string str; while (n--) { scanf ("%s%s" , op, str); if (op[0 ] == 'I' ) insert (str); else printf ("%d\n" , query (str)); } return 0 ; }
第八章 优先队列
p186 哈夫曼编码
priority_queue, 优先队列,默认是大根堆
push() 插入一个元素
top() 返回堆顶元素
pop() 弹出堆顶元素
定义成小根堆的方式:priority_queue<int, vector, greater> q;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <vector> #include <queue> int n, k, res;int main () { priority_queue<int , vector<int >, greater<int >> heap; scanf ("%d" , &n); for (int i = 0 ; i < n; i++) { scanf ("%d" , &k); heap.push (k); } while (heap.size () > 1 ) { int a = heap.top (); heap.pop (); int b = heap.top (); heap.pop (); res += (a + b); heap.push (a+b); } cout << heap.top (); }
第九章 并查集
p199 离线最小值问题
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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 #include <iostream> #include <vector> #include <queue> using namespace std;const int N = 20 ;vector<int > en, in, out; int root[N], dis[N], si[N], is[N], pre[N], post[N], h[N];int n, idx, p;char op[2 ];int findRoot (int x) { while (root[x] != x) x = root[x]; return x; } void Union (int x, int y) { int x_root = findRoot (x); int y_root = findRoot (y); if (x != y) { if (dis[x_root] > dis[y_root]) root[x_root] = y_root; else if (dis[x_root] < dis[y_root]) root[y_root] = x_root; else { root[y_root] = x_root; dis[x_root]++; } } } void mergeIn (int k) { for (int i = 1 ; i <= k; i++) { int cur, index; if (i==1 ) { cur = in[1 ]; index = 0 ; } else { index = en[i-1 ]; cur = in[index + 1 ]; } for (int j = index + 1 ; j <= en[i]; j++) { Union (cur, in[j]); si[cur] = i; is[i]=cur; } } for (int i = 1 ; i < k; i++ ) { pre[i+1 ] = i; post[i] = i + 1 ; } for (int i = 1 ; i <= p; i++) { int name = findRoot (i); int t = si[name]; if (t<=k) { int newset = name; if (is[post[t]]) { Union (name, is[post[t]]); } si[name] = post[t]; is[post[t]] = newset; post[pre[t]] = post[t]; pre[post[t]] = pre[t]; h[t] = i; } } } int main () { scanf ("%d" , &n); p = n; en.push_back (0 ); in.push_back (0 ); while (n--) { scanf ("%s" , op); if (op[0 ] == 'D' ) en.push_back (idx); else { int s = op[0 ] - '0' ; in.push_back (s); idx++; } } for (int i = 1 ; i <= p; i++) { root[i] = i; dis[i] = 0 ; } int len = en.size (); mergeIn (len-1 ); for (int i = 1 ; i <= len-1 ; i++) { cout << h[i] << " " ; } }
p200 朋友圈问题
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 const int N = 20 ;int n, m, root[N], e[N];char op[2 ];int a, b, ans;int findRoot (int x) { while (root[x] != x) x = root[x]; return x; } void Union (int x, int y) { int x_root = findRoot (x); int y_root = findRoot (y); if (x_root!=y_root) root[y_root] = x_root; } int main () { scanf ("%d%d" , &n, &m); for (int i = 1 ; i <= n; i++ ) { root[i] = i; e[i] = 0 ; } while (m--) { scanf ("%s%d%d" , op, &a, &b); if (op[0 ] == 'E' ) { if (e[a] == 0 ) e[a] = b; else Union (e[a], b); if (e[b] == 0 ) e[b] = a; else Union (e[b], a); } else { Union (a, b); } } for (int i = 1 ; i <=n ; i++) { if (root[i] == i) ans++; } cout << ans; }