将数字序列中的某个值移动到序列的左/右端点,输出移动完成后的序列
第一时间想到的是用链表,我就直接用了Java内置的LinkedList,结果发现只能跑50%的测试用例。原因是链表结构的特点在于能快速插入与删除,但查询速度却不高。
查询其他人的做法,发现使用 双链表+哈希表 的组合,可以解决原来只使用链表时查询慢的问题
(个人做题经验并不多,第一次知道有这种组合操作,感叹真是妙啊~)
具体做法是用双链表的结点存储序列值,哈希表的K,V来存储序列值和对应的链表结点
这样一来,要对序列中的某个序列值进行操作时,就可以通过hashMap.get(序列值) 来获得对应的结点,也就知道了其前结点和后结点。有了这些信息,本题链表中删除某个结点的速度就会快上很多
Java代码如下
import java.util.HashMap;
import java.util.Scanner;
public class Main {
static class Node { // 双链表的结点
int value;
Node pre;
Node next;
public Node(int value, Node pre, Node next) {
this.value = value;
this.pre = pre;
this.next = next;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
HashMap<Integer, Node> map = new HashMap<>(); // 哈希表 用于快查
// 完善双链表和哈希表
Node head = new Node(-1, null, null); //头结点
Node tail = new Node(-1, null, null); //尾结点
Node point = head; //指针,初始指向头结点
for (int i = 1; i <= n; i++) {
point.next = new Node(i, null, null); // point后插入新结点
point.next.pre = point; // 新结点的前结点为当前指针
point = point.next; // 更新point位置为新结点
map.put(i, point); //新结点放入哈希表
}
point.next = tail; // 最后一个结点的下一个结点为尾结点
tail.pre = point; // 尾结点的前结点
//输入指令
char[] op = new char[m];
int[] x = new int[m];
for (int i = 0; i < m; i++) {
op[i] = sc.next().charAt(0);
x[i] = sc.nextInt();
}
sc.close();
//执行指令
for(int i=0 ; i<m ; i++) {
//获取要操作的结点
Node node = map.get(x[i]);
//从原链表中取出这个结点
node.next.pre = node.pre;
node.pre.next = node.next;
if(op[i]=='L') {
//结点插入到链表头部
node.next=head.next;
node.pre=head;
head.next=node;
node.next.pre=node;
}else if(op[i]=='R') {
//结点插入到链表尾部
node.pre=tail.pre;
node.next=tail;
tail.pre=node;
node.pre.next=node;
}
}
//输出结果
point = head.next;
while(point.value!= -1) {
System.out.print(point.value+" ");
point = point.next;
}
}
}
运行结果
最后再感叹一下,我是刷题菜鸟,第一次知道了 双链表+哈希表 这种组合用法,它能弥补单一数据结构自身的不足,真的很巧妙