GitHub - September26/java-algorithms: 算法题汇总,包含牛客,leetCode,lintCode等网站题目的解法和代码,以及完整的mode类,甚至链表代码生成工具都有提供。
牛牛拥有一个消息队列,容量无限,为了检测其高效性,特意做了 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;
}
}
}