编程竞赛-消息存取

 目录链接:

力扣编程题-解法汇总_分享+记录-CSDN博客

GitHub同步刷题项目:

GitHub - September26/java-algorithms: 算法题汇总,包含牛客,leetCode,lintCode等网站题目的解法和代码,以及完整的mode类,甚至链表代码生成工具都有提供。

原题链接:登录—专业IT笔试面试备考平台_牛客网

题目描述

牛牛拥有一个消息队列,容量无限,为了检测其高效性,特意做了 n\mathit nn 次操作,指令如下:

首先输入一个字符串表示操作种类,如果字符串为 "in",说明此操作为存消息,接着输入一个正整数 t\mathit tt 以及一个非空且仅由小写字母构成的字符串 s\mathit ss,表示将类型为 t\mathit tt 的消息 s\mathit ss 存入消息队列的末尾;
如果最先输入的字符串为 "out",说明此操作为取消息,接着输入一个非负整数 p\mathit pp,如果 p = 0\mathit p\ =\ \text 0p = 0,则取出当前消息队列中的第一条消息,否则,取出类型为 p\mathit pp 的第一条消息。

如果成功取出消息,则将此消息输出,否则,输出 −1-\text 1−1 表示当前消息队列为空或者没有相应类型的消息。

输入描述:

第一行输入一个正整数 n(3 ≤ n ≤ 2 × 105)\mathit n(\text 3\ \leq\ \mathit n\ \leq\ \text 2\ \times\ \text {10} ^ \text 5)n(3 ≤ n ≤ 2 × 105),表示操作次数。

接下去 n\mathit nn 行,每行输入一条操作指令,首先输入一个字符串 opt\mathit {opt}opt,如果 opt = in\mathit {opt}\ =\ \mathit {in}opt = in,则接着输入一个正整数 t(1 ≤ t ≤ 100)\mathit t(\text 1\ \leq\ \mathit t\ \leq\ \text {100})t(1 ≤ t ≤ 100),以及一个非空且仅由小写字母构成的字符串 s(∣s∣ ≤ 10)\mathit s(\mid\mathit s\mid\ \leq\ \text {10})s(∣s∣ ≤ 10);
如果 opt = out\mathit {opt}\ =\ \mathit{out}opt = out,则接着输入一个非负整数 p(0 ≤ p ≤ 100)\mathit p(\text 0\ \leq\ \mathit p\ \leq\ \text {100})p(0 ≤ p ≤ 100);
opt\mathit {opt}opt 只有上述两种可能,具体含义如题所述。

题目保证,数据中至少有一条取消息操作。

输出描述:

对于每一条取消息操作,一行输出其消息内容,或者输出 −1-\text 1−1。

示例1

输入

复制15 out 0 out 66 in 66 xyh in 99 ivyhole out 3 out 99 in 3 starry in 6 sky in 66 starrysky out 66 out 0 out 3 out 66 out 0 out 0

15
out 0
out 66
in 66 xyh
in 99 ivyhole
out 3
out 99
in 3 starry
in 6 sky
in 66 starrysky
out 66
out 0
out 3
out 66
out 0
out 0

输出

复制-1 -1 -1 ivyhole xyh starry -1 starrysky sky -1

-1
-1
-1
ivyhole
xyh
starry
-1
starrysky
sky
-1

说明

一开始队列中没有消息,因此,最先的两条取消息操作均输出 −1-\text 1−1。

第三、四个操作,依次存入了两条消息,此时,消息队列中的消息排布情况如下:

(66, xyh), (99, ivyhole)(\text {66},\ \mathit {xyh}),\ (\text {99},\ \mathit {ivyhole})(66, xyh), (99, ivyhole)

第五个操作尝试取类型为 3\text 33 的第一条消息,此时队列中没有此类消息,输出 −1-\text 1−1。

第六个操作尝试取类型为 99\text {99}99 的第一条消息,成功取出消息为 "ivyhole"。

第七、八、九个操作,依次存入三条消息,此时,消息队列中的消息排布情况如下:

(66, xyh), (3, starry), (6, sky), (66, starrysky)(\text {66},\ \mathit {xyh}),\ (\text 3,\ \mathit {starry}),\ (\text 6,\ \mathit {sky}),\ (\text {66},\ \mathit {starrysky})(66, xyh), (3, starry), (6, sky), (66, starrysky)

第十个操作,尝试取类型为 66\text {66}66 的第一条消息,成功取出消息 "xyh"。

第十一个操作,取队列中的第一条消息,成功取出 "starry"。

第十二个操作,尝试取类型为 3\text 33 的第一条消息,此时队列中并没有此类消息,输出 −1-\text 1−1。

第十三个操作,尝试取类型为 66\text {66}66 的第一条消息,成功取出 "starrysky"。

第十四个操作,取队列中的第一条消息,成功取出 "sky"。

第十五个操作,由于队列中没有任何消息,所以输出 −1-\text 1−1。

解题思路:

每个消息保存为一个双向链表的节点Node。然后构建一个双向链表和一个map。

map的key为type类型,value为一个类型为Node的队列。

然后进行节点插入链表enqueue和节点移除链表dequeue的操作。

插入链表时,构造一个新的节点,然后将其插入链表中,并且同时加入到其对应类型的队列中。比如类型为1的节点Node,首先把节点Node插入链表尾部。然后从map中查询类型为1的队列,并把这个节点加入到队列中。

移除链表节点时,主要涉及到从链表中删除以及从type对应的队列中删除。如果type=0,则直接移除链表的头节点,并且根据其type类型,找到对应的队列,然后队列的头部出栈。如果type!=0,则根据type找到队列,把头部出栈并获取到这个节点。因为节点是双向链表结构,所以把这个节点的next节点赋值给其pre.next,当前节点就等于从链表中删除。

代码:

import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    Node head = null;
    Node tail = null;
    Map> map = new HashMap<>();

    public static void main(String[] args) {
        // 注意 hasNext 和 hasNextLine 的区别
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        for (int i = 0; i < n; i++) {
            String operation = in.next();
            if ("in".equals(operation)) {
                int type = in.nextInt();
                String message = in.next();
                main.enqueue(type, message);
            } else if ("out".equals(operation)) {
                int type = in.nextInt();
                main.dequeue(type);
            }
        }
    }

    private void enqueue(int type, String value) {
        Node node = new Node(type, value);
        if (head == null) {
            head = node;
        } else {
            tail.next = node;
            node.pre = tail;
        }
        tail = node;
        Queue queue = getOrCreate(map, type);
        queue.add(node);
    }

    private void dequeue(int type) {
        if (head == null) {
            System.out.println("-1");
            return;
        }
        if (0 == type) {
            //删除头节点
            System.out.println(head.value);
            int outType = head.type;
            removeHead();
            Queue queue = getOrCreate(map, outType);
            if (queue.size() == 0) {
                Integer i = null;
                i.compareTo(1);
            }
            queue.poll();
            return;
        }
        Queue queue = getOrCreate(map, type);
        Node poll = queue.poll();
        if (poll != null) {
            System.out.println(poll.value);
            //如果是尾节点
            if (poll == head) {
                removeHead();
            } else if (poll == tail) {
                removeTail();
            } else {
                poll.pre.next = poll.next;
                poll.next.pre = poll.pre;
            }
        } else {
            System.out.println("-1");
        }
    }

    private void removeHead() {
        Node next = head.next;
        if (next != null) {
            next.pre = null;
            head = next;
        } else {
            head = null;
            tail = null;
        }
    }

    private void removeTail() {
        Node pre = tail.pre;
        if (pre != null) {
            pre.next = null;
            tail.pre = null;
            tail = pre;
        } else {
            head = null;
            tail = null;
        }
    }

    private Queue getOrCreate(Map> map, int type) {
        Queue queue = map.get(type);
        if (queue == null) {
            queue = new ArrayDeque<>();
            map.put(type, queue);
        }
        return queue;
    }

    static class Node {
        public int type;
        public String value;
        public Node pre;
        public Node next;

        public Node(int type, String value) {
            this.type = type;
            this.value = value;
        }
    }
}

你可能感兴趣的:(编程题,算法)