链表O(n)80分代码t #8#9,冥间数据ac,有较为详细的解释,求调。
查看原帖
链表O(n)80分代码t #8#9,冥间数据ac,有较为详细的解释,求调。
286496
AzusagawaKaede楼主2021/11/1 13:54

先扫一遍数组,求出所有的“块”,用结构体存储,再用链表串起来。

再扫描链表,每次取出一篮水果。每扫完一遍,检查并清除链表中的空块。不断扫描直到链表为空。

对于“两个相邻且水果类型相同的块变为一个块”,如果合并两个结点,会导致水果的序号难以处理,不建议使用。可以判断每个结点的水果类型是否与其前驱结点的水果类型相同,若相同,则跳过该结点。

需要注意的是,当某个块变成空块时,即使它的前驱结点和后继结点的水果类型相同,仍然要从它的后继节点中取出最左边的水果(详见样例一)。故可以将取水果和删空块分为两个循环执行。

时间复杂度为 O(n)\operatorname{O}(n)

code:code:

#include <bits/stdc++.h>
#define head link[1]
#define tail link[2]
using namespace std;

struct Node{
    int l, len, flag, next, prev;//l为该块中最左边的水果编号,len为水果数
}link[200005];
int tot = 2;

int n, a[200005];
int main()
{
    head = (Node){0, -1, -1, 2,-1}, tail = (Node){0, -1, -1, -1, 1};//链表头尾
    scanf("%d", &n);
    memset(a, 0x3f, sizeof a);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n;)
    {
        int cnt = 0, k = a[i], tmp = i;
        while (a[i] == k)
        {
            cnt++;
            i++;
        }//求块
        tot++;
        link[tot].l = tmp;
        link[tot].len = cnt;
        link[tot].flag = k;
        link[tot].next = 2;
        link[tot].prev = tail.prev;
        link[tail.prev].next = tot;
        tail.prev = tot;//建立结点并插入链表尾部
    }

    while (head.next != 2)//链表不为空
    {
        for (int i = head.next; i != 2; i = link[i].next)
        {
            
            if (link[link[i].prev].flag == link[i].flag) continue;
            printf("%d ", link[i].l);
            link[i].l++;
            link[i].len--;
        }//取水果并输出

        for (int i = head.next; i != 2; i = link[i].next)
        {   
            if (link[i].len == 0)
            {
                link[link[i].prev].next = link[i].next;
                link[link[i].next].prev = link[i].prev;
            }
        }//删空块
        putchar('\n');
        if (link[tail.prev].len == 0)
        {
            tail.prev = link[tail.prev].prev;
            link[tail.prev].next = 2;
        }
    }
    return 0;
}

2021/11/1 13:54
加载中...