日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AcWing算法基础课 Level-2 第二讲 数据结构

發布時間:2025/3/19 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AcWing算法基础课 Level-2 第二讲 数据结构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

單鏈表

826. 單鏈表

#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10;int idx, l[N], r[N], e[N];//在節點a的右邊插入x void insert(int a, int x) {e[idx] = x;l[idx] = a, r[idx] = r[a];l[r[a]] = idx, r[a] = idx ++ ; }//刪除節點a void remove(int a) {r[l[a]] = r[a];l[r[a]] = l[a]; }int main() {//0是左端點,1是右端點l[1] = 0, r[0] = 1, idx = 2;int m;cin >> m;while (m -- ){string op;int k, x;cin >> op;if (op == "L"){cin >> x;insert(0, x);}else if (op == "R"){cin >> x;insert(l[1], x);}else if (op == "D"){cin >> k;remove(k + 1);}else if (op == "IL"){cin >> k >> x;insert(l[k + 1], x);}else {cin >> k >> x;insert(k + 1, x);}}for (int i = r[0]; i != 1; i = r[i]) cout << e[i] << " ";return 0; }

雙鏈表

827. 雙鏈表

#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10;int idx, l[N], r[N], e[N];//在節點a的右邊插入x void insert(int a, int x) {e[idx] = x;l[idx] = a, r[idx] = r[a];l[r[a]] = idx, r[a] = idx ++ ; }//刪除節點a void remove(int a) {r[l[a]] = r[a];l[r[a]] = l[a]; }int main() {//0是左端點,1是右端點l[1] = 0, r[0] = 1, idx = 2;int m;cin >> m;while (m -- ){string op;int k, x;cin >> op;if (op == "L"){cin >> x;insert(0, x);}else if (op == "R"){cin >> x;insert(l[1], x);}else if (op == "D"){cin >> k;remove(k + 1);}else if (op == "IL"){cin >> k >> x;insert(l[k + 1], x);}else {cin >> k >> x;insert(k + 1, x);}}for (int i = r[0]; i != 1; i = r[i]) cout << e[i] << " ";return 0; }

828. 模擬棧

#include <iostream>using namespace std;const int N = 1e5 + 10;int m; int stk[N], tt;int main() {cin >> m;string op;int x;while (m -- ){cin >> op;if (op == "push"){cin >> x;stk[ ++ tt] = x;}else if (op == "pop") -- tt;else if (op == "empty") cout << (tt ? "NO" : "YES") << endl;else cout << stk[tt] << endl;} }

3302. 表達式求值

#include <iostream> #include <stack> #include <unordered_map>using namespace std;stack<int> num; stack<char> op;void eval() {auto b = num.top(); num.pop();auto a = num.top(); num.pop();auto c = op.top(); op.pop();int x;if (c == '+') x = a + b;else if (c == '-') x = a - b;else if (c == '*') x = a * b;else x = a / b;num.push(x); }int main() {unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};string str;cin >> str;for (int i = 0; i < str.size(); i ++ ){char c = str[i];if (isdigit(c)){int x = 0, j = i;while (j < str.size() && isdigit(str[j])) x = x * 10 + str[j ++ ] - '0';i = j - 1;num.push(x);}else if (c == '(') op.push(c);else if (c == ')') // 清空op直到與之對應的左括號{while (op.top() != '(') eval();op.pop();}else // 將op中優先級大于等于它的清空,注意左括號{while (op.size() && op.top() != '(' && pr[op.top()] >= pr[c]) eval();op.push(c);}}while (op.size()) eval();cout << num.top() << endl;return 0; }

隊列

829. 模擬隊列

#include <iostream>using namespace std;const int N = 100010;int m; int q[N], hh, tt = -1;int main() {cin >> m;while (m -- ){string op;int x;cin >> op;if (op == "push"){cin >> x;q[ ++ tt] = x;}else if (op == "pop") hh ++ ;else if (op == "empty") cout << (hh <= tt ? "NO" : "YES") << endl;else cout << q[hh] << endl;}return 0; }

單調棧

830. 單調棧

  • 如果進來的那個?于等于棧頂,說明進來的那個更好(???近),那么棧頂就可以刪掉那么就可以?直刪,直到棧頂?于進來的那個ai,且此時這個stk[tt]就是我要找的那個i的左邊離它最近且?它?的點,做完之后再把ai插到隊列?去
#include <iostream>using namespace std;const int N = 1e5 + 10;int stk[N];int main() {int n;cin >> n;int tt = 0; // tt為0表示棧為空for (int i = 0; i < n; i ++ ){int x;cin >> x;while (tt && stk[tt] >= x) tt -- ;if (!tt) cout << -1 << ' ';else cout << stk[tt] << ' ';stk[ ++ tt] = x;} }

單調隊列

154. 滑動窗口


#include <iostream>using namespace std;const int N = 1e6 + 10;int q[N]; int a[N]; int hh = 0, tt = -1;int main() {int n, k;cin >> n >> k;for (int i = 0; i < n; i ++ ) scanf("%d", a + i);for (int i = 0; i < n; i ++ ){if (hh <= tt && i - q[hh] + 1 > k) hh ++ ;while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;q[ ++ tt] = i;if (i >= k - 1) cout << a[q[hh]] << ' ';}cout << endl;hh = 0, tt = -1;for (int i = 0; i < n; i ++ ){if (hh <= tt && i - q[hh] + 1 > k) hh ++ ;while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;q[ ++ tt] = i;if (i >= k - 1) cout << a[q[hh]] << ' ';} }

KMP

831. KMP字符串



#include <iostream>using namespace std;const int N = 1e5 + 10, M = 1e6 + 10;int n, m; char a[M], b[N]; int ne[N];int main() {cin >> n >> b + 1 >> m >> a + 1;// ne[1] = 0;for (int i = 2, j = 0; i <= n; i ++ ){while (j && b[i] != b[j + 1]) j = ne[j]; // j>0且當前i對應字符不等于ne[j]新拓展出的字符if (b[i] == b[j + 1]) j ++ ;ne[i] = j;}for (int i = 1, j = 0; i <= m; i ++ ){while (j && a[i] != b[j + 1]) j = ne[j]; // j>0且當前i對應。。。if (a[i] == b[j + 1]) j ++ ;if (j == n){cout << i - n << ' ';j = ne[j];}} }

Trie

835. Trie字符串統計

并查集

836. 合并集合

#include <iostream>using namespace std;const int N = 1e5 + 10;int n, m; int p[N];int find(int x) {if (p[x] != x) p[x] = find(p[x]);return p[x]; }int main() {cin >> n >> m;for (int i = 1; i <= n; i ++ ) p[i] = i; // 并查集初始化while (m -- ){char op[2];int a, b;scanf("%s%d%d", op, &a, &b);if (*op == 'M') p[find(a)] = find(b);else{if (find(a) == find(b)) puts("Yes");else puts("No");}} }

837. 連通塊中點的數量

#include <iostream>using namespace std;const int N = 1e5 + 10;int n, m; int fa[N], cnt[N];int find(int x) {if (fa[x] != x) fa[x] = find(fa[x]);return fa[x]; }int main() {cin >> n >> m;for (int i = 1; i <= n; i ++ ) fa[i] = i, cnt[i] = 1;while (m -- ){string op;int a, b;cin >> op;if (op == "C"){cin >> a >> b;a = find(a), b = find(b);if (a != b){fa[a] = b;cnt[b] += cnt[a];}}else if (op == "Q1"){cin >> a >> b;if (find(a) == find(b)) puts("Yes");else puts("No");}else{cin >> a;cout << cnt[find(a)] << endl;}} }

838. 堆排序

  • 二叉堆是一種滿足堆性質的完全二叉樹,因此有父節點與兩個兒子下標之間的關聯
  • 任意一個結點權值都小于等于其父親的權值
  • 堆排序,所以是先把所有數輸進來再進行排序
  • 分析i=n/2,進行down操作時必須滿足左右兒子已經是個堆
  • 分析i=n/2,不能從根結點開始down,要找到一個點滿足以下三個性質(1.左右兒子滿足堆的性質;2.下標最大(因為要往上遍歷);3.不是葉結點(葉結點一定滿足堆的性質))。而n/2是最后一個結點的父節點
  • 注意這里要先有一個cnt去copy n的值,因為在m次pop后元素個數已經不是n了
  • down :先找出左右兒子和父節點三者中最大的,如果最大的不是父節點,那么就將父節點與兒子交換,并且以兒子為父節點遞歸
  • 輸出堆頂操作 :先輸出堆頂,將堆頂用最后元素替換,并將長度-1,并對1號使用down
#include <iostream>using namespace std;const int N = 1e5 + 10;int h[N]; int n, m; int cnt;void down(int u) {int t = u;if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;if (t != u){swap(h[u], h[t]);down(t);} }int main() {cin >> n >> m;for (int i = 1; i <= n; i ++ ) cin >> h[i];cnt = n;for (int i = n / 2; i >= 1; i -- )down(i);while (m -- ){cout << h[1] << ' ';h[1] = h[cnt -- ];down(1);} }

839. 模擬堆

  • 首先要理解的是hp和ph數組存的是什么;hp是heap pointer的縮寫,表示堆數組下標到第k個插入的映射,而ph和hp數組是互為反函數的
  • 那么為什么要用到這兩個數組呢 ?原因是在刪除第k個插入元素的操作時,首先得知道第k個插入元素在堆數組中的下標。因此用ph數組就能知道第k個插入元素在堆數組中的下標,然后再在第k個元素所在的位置進行down和up操作
  • 在swap操作中我們輸入的是堆數組的下標,無法知道堆數組下標對應的是第幾個插入的元素,所以需要hp數組,
#include <iostream>using namespace std;const int N = 1e5 + 10;int h[N], hp[N], ph[N], cnt;void heap_swap(int a, int b) {swap(ph[hp[a]], ph[hp[b]]);swap(hp[a], hp[b]);swap(h[a], h[b]); }void up(int u) {while (u / 2 >= 1 && h[u / 2] > h[u]){heap_swap(u, u / 2);u >>= 1;} }void down(int u) {int t = u;if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;if (t != u){heap_swap(u, t);down(t);} }int main() {int n, m = 0;cin >> n;string op;int k, x;while (n -- ){cin >> op;if (op == "I"){cin >> x;cnt ++ ; // 堆數組中下標m ++ ; // 第m個插入元素ph[m] = cnt, hp[cnt] = m;h[cnt] = x; // 別忘了h數組up(cnt); // 插到末尾所以需要up}else if (op == "PM"){cout << h[1] << endl;}else if (op == "DM"){heap_swap(1, cnt);cnt -- ; // 刪除down(1);}else if (op == "D"){cin >> k;k = ph[k]; // 堆數組中下標為kheap_swap(k, cnt); // 將這兩個下標的結點交換cnt -- ; // 刪除// 上 & 下up(k); // 下標是k的結點down(k);}else{cin >> k >> x;k = ph[k];h[k] = x;// 上 & 下up(k);down(k);}} }

哈希表


840. 模擬散列表

  • 拉鏈法 :
  • 做哈希時,數組?度,也就是模的這個數(上圖1e5),?般要取成?個質數,且要離2的整次冪盡可能遠。在這種情況下,沖突的概率是最?的。
  • 拉鏈法,要用到vector
  • insert函數中,?先要想哈希函數,要把x映射到0到N之間的?個數;x % N 在C++中如果x是負數的話余數是負數,所以再加?個N就?定可以變成正的余數,再模N。得到的k就是我們的哈希值
#include <iostream> #include <cstring>using namespace std;const int N = 1e5 + 3; // 找到的那個質數int h[N], e[N], ne[N], idx;void insert(int x) {int k = (x % N + N) % N;e[idx] = x;ne[idx] = h[k];h[k] = idx ++ ; }bool find(int x) {int k = (x % N + N) % N;for (int i = h[k]; ~i; i = ne[i])if (x == e[i])return true;return false; }int main() {int n;cin >> n;memset(h, -1, sizeof h);while (n -- ){string op;int x;cin >> op >> x;if (op == "I") insert(x);else{if (find(x)) puts("Yes");else puts("No");}} }
  • 開放尋址法 :

  • find函數就是找x所在位置或者如果不存在則返回它應該存儲的位置(也就是在第一次找到的k后第一個為空的位置)。如果循環內找到了上屆,變回0。就是有“找不找得到呢?”的奇妙。
#include <iostream> #include <cstring>using namespace std;const int N = 2e5 + 3, null = 0x3f3f3f3f;int h[N];int find(int x) {int k = (x % N + N) % N;while (h[k] != null && h[k] != x){k ++ ;if (k == N) k = 0;}return k; }int main() {int n;cin >> n;memset(h, 0x3f, sizeof h);while (n -- ){string op;int x, k;cin >> op >> x;k = find(x);if (op == "I") h[k] = x;else{if (h[k] == null) puts("No");else puts("Yes");}} }

841. 字符串哈希




  • p[i]存的是p的i次方,h[i]是字符串前綴哈希值。在讀入詢問前先做預處理
  • 下標從1開始
#include <iostream>using namespace std;typedef unsigned long long ull;const int N = 1e5 + 10, P = 131;int n, m; char str[N]; ull h[N], p[N];ull get(int l, int r) {return h[r] - h[l - 1] * p[r - l + 1]; }int main() {cin >> n >> m >> str + 1;p[0] = 1;for (int i = 1; i <= n; i ++ ){h[i] = h[i - 1] * P + str[i];p[i] = p[i - 1] * P;}while (m -- ){int l1, r1, l2, r2;cin >> l1 >> r1 >> l2 >> r2;if (get(l1, r1) == get(l2, r2)) puts("Yes");else puts("No");} }

總結

以上是生活随笔為你收集整理的AcWing算法基础课 Level-2 第二讲 数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。