|
| 1 | +/* |
| 2 | + * @lc app=leetcode.cn id=432 lang=golang |
| 3 | + * |
| 4 | + * [432] 全 O(1) 的数据结构 |
| 5 | + * |
| 6 | + * https://leetcode-cn.com/problems/all-oone-data-structure/description/ |
| 7 | + * |
| 8 | + * algorithms |
| 9 | + * Hard (35.21%) |
| 10 | + * Likes: 25 |
| 11 | + * Dislikes: 0 |
| 12 | + * Total Accepted: 1.8K |
| 13 | + * Total Submissions: 5.1K |
| 14 | + * Testcase Example: '["AllOne","getMaxKey","getMinKey"]\n[[],[],[]]' |
| 15 | + * |
| 16 | + * 实现一个数据结构支持以下操作: |
| 17 | + * |
| 18 | + * |
| 19 | + * Inc(key) - 插入一个新的值为 1 的 key。或者使一个存在的 key 增加一,保证 key 不为空字符串。 |
| 20 | + * Dec(key) - 如果这个 key 的值是 1,那么把他从数据结构中移除掉。否者使一个存在的 key 值减一。如果这个 key |
| 21 | + * 不存在,这个函数不做任何事情。key 保证不为空字符串。 |
| 22 | + * GetMaxKey() - 返回 key 中值最大的任意一个。如果没有元素存在,返回一个空字符串""。 |
| 23 | + * GetMinKey() - 返回 key 中值最小的任意一个。如果没有元素存在,返回一个空字符串""。 |
| 24 | + * |
| 25 | + * |
| 26 | + * 挑战:以 O(1) 的时间复杂度实现所有操作。 |
| 27 | + * |
| 28 | + */ |
| 29 | + |
| 30 | +/* |
| 31 | + * 这个题目与155最小栈那题有点类似,但是有点不同的是每次加减1,分析一下: |
| 32 | + * 1. 必然需要一个hash结构,key输入的key,value中除数值外,一般可以带上一个指针指向其他数据结构的节点 |
| 33 | + * 2. 需要保存最大最小值,注意这不是一个值,而是动态变化的一系列值,某个最大值变小之后要将次大的推上来, |
| 34 | + * 那么可选数组、链表等各种结构,hash的值指向这个节点,帮助快速定位 |
| 35 | + * 3. 另外一个点是加减1这个操作,加减1之后元素可能前移可能后移,移动的时候都是跨过相等的一批值, |
| 36 | + * 如果将相同值的元素放在同一个节点上,每个节点是一个层的概念,那么移动的话只需要移动到前后层即可。 |
| 37 | + * 这时候引入一个新问题,就是如何快速定位到目标点上,想当然就是hash的value中保存目标点的指针, |
| 38 | + * 另外同一层内没有移动操作,只有O(1)的查找,所以每层只需要一个hash保存即可 |
| 39 | + */ |
| 40 | + |
| 41 | +// @lc code=start |
| 42 | +import ( |
| 43 | + "container/list" |
| 44 | +) |
| 45 | + |
| 46 | +type Node struct { |
| 47 | + Key string |
| 48 | + Value int |
| 49 | + Level *Level |
| 50 | +} |
| 51 | +type Level struct { |
| 52 | + Value int |
| 53 | + Nodes map[string]bool |
| 54 | + Element *list.Element // 快速定位到链表节点,用以查找前后节点 |
| 55 | +} |
| 56 | + |
| 57 | +type AllOne struct { |
| 58 | + Data map[string]*Node |
| 59 | + Rank *list.List |
| 60 | +} |
| 61 | + |
| 62 | +/** Initialize your data structure here. */ |
| 63 | +func Constructor() AllOne { |
| 64 | + return AllOne{ |
| 65 | + Data: map[string]*Node{}, |
| 66 | + Rank: list.New(), |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +/** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */ |
| 71 | +func (this *AllOne) Inc(key string) { |
| 72 | + node, ok := this.Data[key] |
| 73 | + if !ok { |
| 74 | + needInsert := false |
| 75 | + var level *Level |
| 76 | + front := this.Rank.Front() |
| 77 | + // 空或者队头value大于1都需要插入 |
| 78 | + if front == nil { |
| 79 | + needInsert = true |
| 80 | + } else if level = front.Value.(*Level); level.Value > 1 { |
| 81 | + needInsert = true |
| 82 | + } |
| 83 | + if needInsert { |
| 84 | + level = &Level{Value: 1, Nodes: map[string]bool{}} |
| 85 | + el := this.Rank.PushFront(level) |
| 86 | + level.Element = el |
| 87 | + } |
| 88 | + level.Nodes[key] = true |
| 89 | + node := &Node{Key: key, Value: 1, Level: level} |
| 90 | + this.Data[key] = node |
| 91 | + return |
| 92 | + } |
| 93 | + node.Value++ |
| 94 | + originLevel := node.Level |
| 95 | + needInsert := false |
| 96 | + var nextLevel *Level |
| 97 | + nextLevelElement := originLevel.Element.Next() |
| 98 | + // 队尾或者下一个的value不是目标值,需要插入新节点 |
| 99 | + if nextLevelElement == nil { |
| 100 | + needInsert = true |
| 101 | + } else if nextLevel = nextLevelElement.Value.(*Level); nextLevel.Value > node.Value { |
| 102 | + needInsert = true |
| 103 | + } |
| 104 | + if needInsert { |
| 105 | + nextLevel = &Level{Value: node.Value, Nodes: map[string]bool{}} |
| 106 | + el := this.Rank.InsertAfter(nextLevel, originLevel.Element) |
| 107 | + nextLevel.Element = el |
| 108 | + } |
| 109 | + |
| 110 | + // 设置到新level |
| 111 | + nextLevel.Nodes[node.Key] = true |
| 112 | + node.Level = nextLevel |
| 113 | + // 清理原level |
| 114 | + delete(originLevel.Nodes, node.Key) |
| 115 | + if len(originLevel.Nodes) <= 0 { |
| 116 | + this.Rank.Remove(originLevel.Element) |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +/** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */ |
| 121 | +func (this *AllOne) Dec(key string) { |
| 122 | + node, ok := this.Data[key] |
| 123 | + if !ok { |
| 124 | + return |
| 125 | + } |
| 126 | + node.Value-- |
| 127 | + if node.Value <= 0 { // 删除节点 |
| 128 | + delete(this.Data, key) |
| 129 | + delete(node.Level.Nodes, key) |
| 130 | + if len(node.Level.Nodes) <= 0 { |
| 131 | + this.Rank.Remove(node.Level.Element) |
| 132 | + } |
| 133 | + return |
| 134 | + } |
| 135 | + originLevel := node.Level |
| 136 | + prevLevelElement := originLevel.Element.Prev() |
| 137 | + |
| 138 | + needInsert := false |
| 139 | + var prevLevel *Level |
| 140 | + if prevLevelElement == nil { |
| 141 | + needInsert = true |
| 142 | + } else if prevLevel = prevLevelElement.Value.(*Level); prevLevel.Value < node.Value { |
| 143 | + needInsert = true |
| 144 | + } |
| 145 | + if needInsert { |
| 146 | + prevLevel = &Level{Value: node.Value, Nodes: map[string]bool{}} |
| 147 | + el := this.Rank.InsertBefore(prevLevel, originLevel.Element) |
| 148 | + prevLevel.Element = el |
| 149 | + } |
| 150 | + // 设置到新level |
| 151 | + prevLevel.Nodes[node.Key] = true |
| 152 | + node.Level = prevLevel |
| 153 | + // 清理原level |
| 154 | + delete(originLevel.Nodes, node.Key) |
| 155 | + if len(originLevel.Nodes) <= 0 { |
| 156 | + this.Rank.Remove(originLevel.Element) |
| 157 | + } |
| 158 | +} |
| 159 | + |
| 160 | +/** Returns one of the keys with maximal value. */ |
| 161 | +func (this *AllOne) GetMaxKey() string { |
| 162 | + maxLevelElement := this.Rank.Back() |
| 163 | + if maxLevelElement == nil { |
| 164 | + return "" |
| 165 | + } |
| 166 | + maxLevel := maxLevelElement.Value.(*Level) |
| 167 | + for k := range maxLevel.Nodes { |
| 168 | + return k |
| 169 | + } |
| 170 | + return "" |
| 171 | +} |
| 172 | + |
| 173 | +/** Returns one of the keys with Minimal value. */ |
| 174 | +func (this *AllOne) GetMinKey() string { |
| 175 | + minLevelElement := this.Rank.Front() |
| 176 | + if minLevelElement == nil { |
| 177 | + return "" |
| 178 | + } |
| 179 | + minLevel := minLevelElement.Value.(*Level) |
| 180 | + for k := range minLevel.Nodes { |
| 181 | + return k |
| 182 | + } |
| 183 | + return "" |
| 184 | +} |
| 185 | + |
| 186 | +/** |
| 187 | + * Your AllOne object will be instantiated and called as such: |
| 188 | + * obj := Constructor(); |
| 189 | + * obj.Inc(key); |
| 190 | + * obj.Dec(key); |
| 191 | + * param_3 := obj.GetMaxKey(); |
| 192 | + * param_4 := obj.GetMinKey(); |
| 193 | + */ |
| 194 | +// @lc code=end |
0 commit comments