这个和146题 LRU缓存的思路有点类似
纯自己想+写。改了十来次。最后结果接近双百
双向链表+哈希map
双向链表预留一个head和tail。
Solution类里有一个min变量来表示当前的出现次数最小值,max变量来表示当前的出现次数的最大值。min和max很重要,因为影响到出现次数最多和出现次数最少的字符串的有序性(head的后一个一定是出现次数最多的,tail的前一个一定是出现次数最少的,这个是核心思想)
如果增加一个新字符串,要进行判断,map里面如果没有这个字符串,就直接把这个字符串加到双向链表的尾部。如果map里面有这个字符串,就需要判断一下,字符串出现的次数与当前的最大次数和最小次数,如果出现次数大于当前最大次数max的值,则更新最大次数,如果字符串出现的次数比当前最小次数min的值要大,就要更新最小次数。
要注意的是,在增加的时候,只有当前这个字符串是min变量的时候,才需要去更新min的值,因为他可能有一个或者多个与min的值相等的Node节点,在这个字符串是min变量的时候,这个字符串的计数已经增加1了,就不会是min变量了,要从tail开始向前遍历,重新寻找一个min变量。如果当前这个字符串不是min变量,随便增加,不会影响min变量的意义,min变量还是表示出现次数最少的那个字符串。
减少一个字符串的时候同理。
只有当前这个字符串是max变量的时候,才需要去更新max的值,要从head开始向后遍历,重新寻找一个max变量。
查询字符串的时候,如果是查询出现次数最多的字符串,就返回head.next的值;如果是查询出现次数最少的字符串,就返回tail.pre的值。 因为在增加和减少一个字符串的时候,已经保证出现次数最多和出现次数最少的字符串的有序性
class AllOne {
DoubleLinkedList doubleLinkedList;
Map<String, Node> map;
Node min = new Node(null, Integer.MAX_VALUE);
Node max = new Node(null, 0);
public AllOne() {
doubleLinkedList = new DoubleLinkedList();
map = new HashMap<String, Node>();
}
public void inc(String key) {
if(!map.containsKey(key)) {
Node node = new Node(key, 1);
doubleLinkedList.addNodeLast(node);
min = node;
map.put(key, node);
}else {
Node node = map.get(key);
node.times++;
if(node != max && node.times > max.times) {
max = node;
doubleLinkedList.delNode(node);
doubleLinkedList.addNodeFirst(node);
}
if(node == min){
Node temp = doubleLinkedList.tail;
doubleLinkedList.delNode(min);
while(temp.pre != doubleLinkedList.head && temp.pre.times < node.times){
temp = temp.pre;
}
doubleLinkedList.addNodeBeforeNode(temp, node);
min = doubleLinkedList.tail.pre;
}
}
}
public void dec(String key) {
Node node = map.get(key);
node.times--;
if(node.times == 0) {
map.remove(key);
doubleLinkedList.delNode(node);
if(min == node){
min = doubleLinkedList.tail.pre;
}
return;
}
if(node != min && node.times < min.times) {
min = node;
doubleLinkedList.delNode(node);
doubleLinkedList.addNodeLast(node);
}
if(node == max){
doubleLinkedList.delNode(node);
Node temp = doubleLinkedList.head;
while(temp.next.times > node.times){
temp = temp.next;
}
doubleLinkedList.addNodeAfterNode(temp, node);
max = doubleLinkedList.head.next;
}
}
public String getMaxKey() {
if(map.isEmpty()) {
return "";
}
return doubleLinkedList.head.next.str;
}
public String getMinKey() {
if(map.isEmpty()) {
return "";
}
return doubleLinkedList.tail.pre.str;
}
}
class DoubleLinkedList{
Node head;
Node tail;
public DoubleLinkedList() {
head = new Node(null, -1);
tail = new Node(null, -1);
head.next = tail;
tail.pre = head;
}
public void addNodeFirst(Node node) {
Node tempNode = head.next;
head.next = node;
node.pre = head;
node.next = tempNode;
tempNode.pre = node;
}
public void addNodeLast(Node node) {
Node tempNode = tail.pre;
tempNode.next = node;
node.pre = tempNode;
node.next = tail;
tail.pre = node;
}
public void delNode(Node node) {
Node before = node.pre;
Node after = node.next;
before.next = after;
after.pre = before;
}
public void addNodeAfterNode(Node before, Node node){
Node temp = before.next;
before.next = node;
node.pre = before;
node.next = temp;
temp.pre = node;
}
public void addNodeBeforeNode(Node after, Node node){
Node temp = after.pre;
temp.next = node;
node.pre = temp;
node.next = after;
after.pre = node;
}
}
class Node{
String str;
int times;
Node pre;
Node next;
public Node(String str, int times) {
this.str = str;
this.times = times;
}
}
结果