目录链接:
力扣编程题-解法汇总_分享+记录-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<Integer, Queue<Node>> 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<Node> 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<Node> queue = getOrCreate(map, outType);if (queue.size() == 0) {Integer i = null;i.compareTo(1);}queue.poll();return;}Queue<Node> 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<Node> getOrCreate(Map<Integer, Queue<Node>> map, int type) {Queue<Node> 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;}}
}