题目:
请你设计一个用于存储字符串计数的数据结构,并能够返回计数最小和最大的字符串。
实现 AllOne 类:
AllOne()初始化数据结构的对象。inc(String key)字符串key的计数增加1。如果数据结构中尚不存在key,那么插入计数为1的key。dec(String key)字符串key的计数减少1。如果key的计数在减少后为0,那么需要将这个key从数据结构中删除。测试用例保证:在减少计数前,key存在于数据结构中。getMaxKey()返回任意一个计数最大的字符串。如果没有元素存在,返回一个空字符串""。getMinKey()返回任意一个计数最小的字符串。如果没有元素存在,返回一个空字符串""。
注意: 每个函数都应当满足 O(1) 平均时间复杂度。
算法:
方法一:hash table + 双向链表
双向链表从头到尾按字符次数递增存储,hash table存储字符在双向链表中的地址。因为inc和dec每次只对频率变化1,确实可以在O(1)时间内做到。
完全考察代码实现能力
import "math"
type AllOne struct {
Map map[string]*Node
LinkedListHead *Node // 双向链表头,哨兵
LinkedListTail *Node // 双向链表尾,哨兵
}
type Node struct {
Pre *Node
Next *Node
Str string
Count int
}
func Constructor() AllOne {
head := &Node{Count:0}
tail := &Node{Count:math.MaxInt64}
head.Next = tail
tail.Pre = head
return AllOne{
Map: make(map[string]*Node),
LinkedListHead: head,
LinkedListTail: tail,
}
}
// Map中不存在这个key,插入head之后
// 存在,node.Count++,找到链表后面node.Count更小的node,交换位置
func (this *AllOne) Inc(key string) {
node, ok := this.Map[key]
if !ok {
node = &Node{
Str: key,
Count: 1,
}
this.Map[key] = node
this.LinkedListHead.Next.Pre = node
node.Next = this.LinkedListHead.Next
node.Pre = this.LinkedListHead
this.LinkedListHead.Next = node
} else {
node.Count ++
// pre-node-next-nNext交换node和next的位置
for node.Count > node.Next.Count {
next := node.Next
next.Next.Pre = node
node.Next = next.Next
node.Pre.Next = next
next.Pre = node.Pre
node.Pre = next
next.Next = node
}
}
}
func (this *AllOne) Dec(key string) {
node := this.Map[key]
if node.Count == 1 {
node.Pre.Next = node.Next
node.Next.Pre = node.Pre
node.Next = nil
node.Pre = nil
delete(this.Map, key)
} else {
node.Count --
// ppre-pre-node-next交换pre和node的位置
for node.Count < node.Pre.Count {
pre := node.Pre
pre.Next = node.Next
node.Next.Pre = pre
pre.Pre.Next = node
node.Pre = pre.Pre
node.Next = pre
pre.Pre = node
}
}
}
// 取双向链表最后一个元素
func (this *AllOne) GetMaxKey() string {
if this.LinkedListTail.Pre.Str != "" {
return this.LinkedListTail.Pre.Str
}
return ""
}
// 取双向链表第一个元素
func (this *AllOne) GetMinKey() string {
if this.LinkedListHead.Next.Str != "" {
return this.LinkedListHead.Next.Str
}
return ""
}