PAT – ADVANCED – 25POINTS (UPDATING)

A1051 出栈序列

①按序一直进栈,添加元素应查容量防止超限
②栈顶元素和序列匹配上,就可以继续下次匹配

#include <iostream>
#include <stack>
using namespace std;

int main() {
    int M, N, K, c, k;
    int s[1000];
    stack<int> stk;
    bool f;
    scanf("%d%d%d", &M, &N, &K);

    for (int i = 0; i < K; i++) {
        c = k = 0;
        f = true;
        for (int j = 0; j < N; j++)
            scanf("%d", &s[j]);
        while (!stk.empty())
            stk.pop();

        while (c < N) {
            stk.push(++c);
            if (stk.size() > M) {
                f = false;
                break;
            }
            while (!stk.empty() && stk.top() == s[k]) {
                stk.pop();
                k++;
            }
        }

        if (stk.empty() && f) printf("YES\n");
        else printf("NO\n");
    }

    return 0;
}

队列

A1056 顺序对决

①每组决出赢家继续对决,每轮按序对决,符合FIFO使用队列,队列q按序保存当前轮选手
②解决晋级问题:每轮清空q,晋级的人存入q1,下一轮将q置为q1。总对决轮数 $\scriptsize ct0 = \left \lceil \frac{np}{ng} \right \rceil$
③解决分组问题:每轮 $\scriptsize ct = \left \lceil \frac{q.size()}{ng} \right \rceil$ 组,每ng个人按序比大小,最后不满ng时队列空则跳出,实现最后一组无论几个人自成一组。
④解决标号问题:淘汰的人给其标号n,倒置循环即 $\scriptsize n = ct + 1$
⑤何时结束:队列中仅有一个元素时决出最终赢家
吐槽:本题描述!第一次读的时候没懂哇……又臭又长又难懂,(ヘ・_・)ヘ┳━┳,全靠样例猜

#include <iostream>
#include <bits/stdc++.h>
#include <queue>
using namespace std;

int main() {
    int np, ng, tp, maxi;
    queue<int> q;
    queue<int> q1;
    scanf("%d%d", &np, &ng);
    int w[np], n[np];
    memset(n, 0, sizeof(n));
    for (int i = 0; i < np; i++)
        scanf("%d", &w[i]);
    for (int i = 0; i < np; i++) {
        scanf("%d", &tp);
        q.push(tp);
    }

    while (q.size() > 1) {
        int ct = q.size() % ng ? q.size() / ng + 1 : q.size() / ng;
        for(int k = ct; k > 0; k--) {
            maxi = q.front();
            for (int i = 0; i < ng; i++) {
                if (!q.empty()) {
                    tp = q.front();
                    if (w[maxi] < w[tp]) {
                        n[maxi] = ct + 1;
                        maxi = tp;
                    }
                    else if(w[maxi] > w[tp])
                        n[tp] = ct + 1;
                    q.pop();
                }
                else break;
            }
            q1.push(maxi);
        }

        while(!q1.empty()) {
            q.push(q1.front());
            q1.pop();
        }
    }

    n[q.front()]++;
    int i = 0;
    for (; i < np - 1; i++)
        printf("%d ", n[i]);
    printf("%d\n", n[i]);

    return 0;
}

链表

A1061 反转链表

该题需解决下述问题:
①如何表示链表
②如何反转链表:递归、栈迭代和迭代法,此处使用迭代法。要使当前节点cur指向前一节点pre,必须提前保存pre;而修改当前节点指针会导致丢失指向后续链表指针,故还需保存后续节点next
③如何控制分段数量
④解决分段之间的反转
⑤解决首尾问题

A1032 相交链表

此题所给数据特殊,链表无环且单串内无重复字符,即为找相同节点问题,以下给出双指针实现:
哈希表 第一串读入各字符存set,第二串依次到set匹配即可
时间 $\scriptsize O(n_1+n_2)$,空间 $\scriptsize O(n_1)$
双指针 指向两个串头的指针同时依次比对后移,两指针必在等长两串相交处相遇。两串长度不同时还想用此方法,就要 构造等长串 使得两指针在相交处相遇,设两串公共长度 $\scriptsize l$,各自的非公共长度 $\scriptsize a$ 和 $\scriptsize b$,则两串长度分别为 $\scriptsize l + a$ 和 $\scriptsize l + b$,分别叠加对方的非公共长度即可构造相交处为末尾的相等长度 $\scriptsize l + a + b$ ,妙蛙!
时间 $\scriptsize O(n_1+n_2)$,空间 $\scriptsize O(1)$

#include <iostream>
using namespace std;

const int maxn = 100001;

struct Node {
    char letr;
    int next;
    Node(char letr, int next) : letr(letr), next(next) {}
} *node[maxn];

int main() {
    int H1, H2, N;
    scanf("%d%d%d", &H1, &H2, &N);
    if (H1 == -1 || H2 == -1) {
        printf("-1\n");
        return 0;
    }

    int a, n; char d;
    while (~scanf("%d %c %d", &a, &d, &n))
        node[a] = new Node(d, n);

    int p1 = H1, p2 = H2;
    while (p1 != p2) {
        p1 = p1 == -1 ? H2 : node[p1]->next;
        p2 = p2 == -1 ? H1 : node[p2]->next;
    }

    if (p1 == -1) printf("-1\n");
    else printf("%05d\n", p1);

    return 0;
}

A1052 排序链表

十大排序方法中,归并排序和快速排序时间最优,为 $\scriptsize O(nlogn)$,下先给出链表归并排序方法,然而本题可使用库函数sort避免写复杂的逻辑

归并排序

①划分子链表:
a)划分子集[low,mid)、[mid,high]要找到链表中点mid,方法是使用双指针,使指针位移fast:slow=2,fast到末尾,slow即为中点mid
b)节点个数为0或1时自成序,空直接返回,单节点要断掉后续,否则将返回该节点为头的链表
①归并两条有序链表:超过单节点的子链表使用双指针依次比较后移方法筛选出后一节点,挂到记录的尾节点上去
此解法暂未计数有效节点(未排除不在链表中的节点)

#include <iostream>
using namespace std;

const int maxn = 100001;

struct Node {
    int addr;
    int key;
    int next;
    Node(int addr, int key, int next) : addr(addr), key(key), next(next) {}
} * node[maxn];

Node *merge(Node *l, Node *r) {
    Node *vHead = new Node(-1, -1, -1);
    Node *cur = vHead;
    while (l && r) {
        if (l->key <= r->key) {
            cur->next = l->addr;
            l = node[l->next];
        }
        else {
            cur->next = r->addr;
            r = node[r->next];
        }
        cur = node[cur->next];
    }
    cur->next = l ? l->addr : r ? r->addr : -1;
    return node[vHead->next];
}

Node *part(Node *lo, Node *hi) {
    if (lo == nullptr)
        return lo;
    if (node[lo->next] == hi) {
        lo->next = -1;
        return lo;
    }
    Node *fast = lo, *slow = lo;
    while (fast != hi) {
        slow = node[slow->next];
        fast = node[fast->next];
        if (fast != hi)
            fast = node[fast->next];
    }
    return merge(part(lo, slow), part(slow, hi));
}

int main() {
    int H, N;
    scanf("%d%d", &H, &N);

    int a, k, n;
    while (~scanf("%d%d%d", &a, &k, &n))
        node[a] = new Node(a, k, n);

    Node *h = part(node[H], nullptr);

    printf("%d %05d\n", cnt, h->addr);
    for (; node[h->next]; h = node[h->next])
        printf("%05d %d %05d\n", h->addr, h->key, h->next);
    printf("%05d %d -1\n", h->addr, h->key);

    return 0;
}

A1097 去重链表

使用 尾插法,用两条静态链表分别保存去重链表和重复链表
①两条链表:分别记录去重、重复链表头H、R和尾tailH、tailR
②检重加尾:每次检测set中是否已有当前元素,筛出当前节点cur作为新的尾部tail=cur并修改tail.next=-1,修改tail.next要提前保存 防止后继指针丢失
③边界输入:空链表、不重链表、全重链表、单元素链表

#include <iostream>
#include <cmath>
#include <unordered_set>
using namespace std;

const int maxn = 100001;

struct Node {
    int addr;
    int key;
    int next;
    Node(int addr, int key, int next) : addr(addr), key(key), next(next) {}
} *node[maxn];

int main() {
    int H, N, R = -1;
    scanf("%d%d", &H, &N);

    int a, k, n;
    while (~scanf("%d%d%d", &a, &k, &n))
        node[a] = new Node(a, k, n);

    unordered_set<int> st;
    Node *cur = node[H], *tailH = nullptr, *tailR = nullptr;
    while (cur) {
        k = abs(cur->key);
        if (!st.count(k)) {
            st.insert(k);
            if (tailH) tailH->next = cur->addr;
            tailH = cur;
            cur = node[cur->next];
            tailH->next = -1;
        }
        else {
            if (tailR == nullptr) R = cur->addr;
            else tailR->next = cur->addr;
            tailR = cur;
            cur = node[cur->next];
            tailR->next = -1;
        }
    }

    Node *h;
    for (h = node[H]; node[h->next]; h = node[h->next])
        printf("%05d %d %05d\n", h->addr, h->key, h->next);
    printf("%05d %d -1\n", h->addr, h->key, h->next);

    if (R != -1) {
        for (h = node[R]; node[h->next]; h = node[h->next])
            printf("%05d %d %05d\n", h->addr, h->key, h->next);
        printf("%05d %d -1\n", h->addr, h->key);
    }

    return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

©2018-2024 Howell版权所有 备案号:冀ICP备19000576号