2022.01.29刷题
acwing基础课 II 数据结构
链表
数组模拟单链表
int idx, head, ne[N5], e[N5];
int main() {
    int n = read(), k, x;
    head = -1; //初始化头结点
    char op;
    while (n--) {
        scanf("%c", &op);
        k = read();
        if (op == 'H') {
            e[idx] = k;
            ne[idx] = head;
            head = idx++;
        }
        else if (op == 'D') {
            if (k == 0) { head = ne[head]; }
            else ne[k - 1] = ne[ne[k - 1]];
        }
        else {
            x = read();
            ne[idx] = ne[k - 1];
            ne[k - 1] = idx;
            e[idx++] = x;
        }
    }
    while (head != -1) {
        O(e[head]);
        head = ne[head];
    }
    return 0;
}
数组模拟双链表
int idx, head, l[N5], e[N5], r[N5];
void init() {
    r[0] = 1, l[1] = 0, idx = 2;
}
void insert(int k, int x) {
    l[idx] = k, r[idx] = r[k], e[idx] = x;
    l[r[k]] = idx, r[k] = idx++;
}
void remove(int k) {
    r[l[k]] = r[k], l[r[k]] = l[k];
}
int main() {
    init();
    int k, x, m = read();
    string op;
    while (m--) {
        cin >> op;k = read();
        if (op[0] == 'R') insert(l[1], k);
        else if (op[0] == 'L') insert(0, k);
        else if (op[0] == 'I') {
            x = read();
            if (op[1] == 'R') insert(k + 1, x);
            else insert(l[k + 1], x);
        }
        else  remove(k + 1);
    }
    head = r[head];
    while (head != 1) O(e[head]), head = r[head];
    return 0;
}
栈 & 队列 & 单调..
模拟栈
雪菜有的是 从 tt=0 不知道有没有影响.
然后empty() 是 tt>0
int stk[N5], tt = -1; //记住下标是从 -1 开始的
void push(int x) {
    stk[++tt] = x;
}
void pop() {
    --tt;
}
int query() {
    return stk[tt];
}
bool empty() {
    return tt == -1;
}
模拟队列
尾进 头出.  tt=-1, hh = 0
int q[N5], tt = -1, hh;
void push(int x) {
    q[++tt] = x;
}
void pop() {
    ++hh;
}
int query() {
    return q[hh];
}
bool empty() {
    return hh > tt;
}
单调栈
输出每个数左边第一个比他小的数. => 单增的栈.
int a[N6], tt;
int main() {
    int n = read(), x;
    rep(i, 0, n) {
        x = read();
        while (tt && a[tt] >= x) tt--; //如果大于就弹出, 永无出头之日.
        if (tt) O(a[tt]); //如果栈中还有数: 就输出
        else O(-1);
        a[++tt] = x; // 当前数 入栈.
    }
    return 0;
}
单调队列(双端)
滑动窗口最大值和最小值.
int a[N6], q[N6], tt = -1, hh;
int main() {
    int n = read(), k = read();
    rep(i, 0, n) a[i] = read();
    rep(i, 0, n) {
        if (hh <= tt && i - k + 1 > q[hh]) hh++; // 如果左边不对, 出栈.
        while (hh <= tt && a[q[tt]] >= a[i]) tt--; //最小值, 单增区间
        q[++tt] = i;
        if (i - k + 1 >= 0) O(a[q[hh]]);
    }
    puts("");
    tt = -1, hh = 0;
    rep(i, 0, n) {
        if (hh <= tt && i - k + 1 > q[hh]) hh++;
        while (hh <= tt && a[q[tt]] <= a[i]) tt--; //最大值, 单减区间
        q[++tt] = i;
        if (i - k + 1 >= 0) O(a[q[hh]]);
    }
    return 0;
}
栈. 表达式求值 ★★★★
不会做... 不过这个顺序..
stack<int> op;
stack<int> num;
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> pri = { {'+',1},{'-',1},
            {'*',2},{'/',2} };
    string equ;
    cin >> equ;
    for (int i = 0;i < equ.size();i++) {
        auto c = equ[i];
        if (isdigit(c)) {
            int x = 0, j = i;
            while (j < equ.size() && isdigit(equ[j]))
                x = x * 10 + equ[j++] - '0';
            i = j - 1; num.push(x);
        }
        else if (c == '(') op.push(c);
        else if (c == ')') {
            while (op.top() != '(') eval();
            op.pop();
        }
        else {
            while (op.size() && op.top() != '(' &&
                pri[op.top()] >= pri[c]) eval();
            op.push(c);
        }
    }
    while (op.size()) eval();
    cout << num.top() << endl;
    return 0;
}
KMP ★★★★
int n, m;
int ne[N5];
char s[N6], p[N5];
int main() {
    cin >> n >> p + 1 >> m >> s + 1; 
    for (int i = 2, j = 0; i <= n; i++) {
        while (j && p[i] != p[j + 1]) j = ne[j];
        if (p[i] == p[j + 1]) j++; //求next 就是子串和自己匹配.
        ne[i] = j;
    }
    da(ne, n + 2);
    for (int i = 1, j = 0; i <= m; i++) {
        while (j && s[i] != p[j + 1]) j = ne[j];
        if (s[i] == p[j + 1]) j++;
        if (j == n) {
            O(i - n); j = ne[j];
        }
    }
    return 0;
}
数组元素的目标和
双指针
int a[N5], b[N5];
int main() {
    int n = read(), m = read(), x = read();
    rep(i, 0, n) a[i] = read();
    rep(i, 0, m) b[i] = read();
    int r = m - 1;
    rep(l, 0, n) {
        while (r >= 0 && a[l] + b[r] > x) r--;
        if (a[l] + b[r] == x) {
            O(l), O(r);
            return 0;
        }
    }
    return 0;
}
判断子序列
双指针
int a[N5], b[N5];
int main() {
    int m = read(), n = read();
    int j = 0;
    rep(i, 0, m) b[i] = read();
    rep(i, 0, n) a[i] = read();
    rep(i, 0, n) {
        if (j < m && b[j] == a[i]) j++;
    }
    puts(j == m ? "Yes" : "No");
    return 0;
}
Tire树
快速 存储字符串集合的数据结构
int son[N5][26], cnt[N5], idx; //idx为0的那个是根 空串 "";
char str[N5];
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() {
    int n = read();
    while (n--) {
        char op[2];
        scanf("%s%s", op, str);
        if (*op == 'I') insert(str);
        else printf("%d\n", query(str));
    }
    return 0;
}
最大异或对.
int a[N5], idx;
int son[N6 * 3][2]; //这里为什么需要 N6*3 个?
void insert(int x) {
    int p = 0;
    per(i, 31, 0) {
        int& s = son[p][x >> i & 1];
        if (!s) s = ++idx;
        p = s;
    }
}
int search(int x) {
    int p = 0, res = 0;
    per(i, 31, 0) {
        int s = x >> i & 1;
        if (son[p][!s]) {
            res += 1 << i; //这里为什么是这样子的...
            p = son[p][!s];
        }
        else p = son[p][s];
    }
    return res;
}
int main() {
    int n = read();
    rep(i, 0, n)a[i] = read(), insert(a[i]);
    int res = 0;
    rep(i, 0, n) {
        res = max(res, search(a[i]));
    }
    O(res);
    return 0;
}
并查集
合并集合
int p[N5];
int find(int k) {
    if (p[k] != k) p[k] = find(p[k]);
    return p[k];
}
int main() {
    int n = read(), m = read();
    rep(i, 1, n + 1) {
        p[i] = i;
    }
    rep(i, 0, m) {
        char op[2]; scanf("%s", op);
        int l = read(), r = read();
        if (op[0] == 'M') p[find(l)] = find(r);
        else
            puts(find(l) == find(r) ? "Yes" : "No");
    }
    return 0;
}
837. 连通块中点的数量
int p[N5], cnt[N5];
int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}
int main() {
    int n = read(), m = read();
    rep(i, 1, n + 1) p[i] = i, cnt[i] = 1;
    rep(i, 0, m) {
        char op[4];
        scanf("%s", op);  int l = read();
        if (op[0] == 'C') {
            int r = read();
            l = find(l), r = find(r);
            if (l != r) {
                cnt[l] += cnt[r];
                p[r] = l;
            }
        }
        else if (op[1] == '1') {
            int r = read();
            puts(find(r) == find(l) ? "Yes" : "No");
        }
        else {
            printf("%d\n", cnt[find(l)]);
        }
    }
    return 0;
}
食物链

                
            
        
浙公网安备 33010602011771号