golang力扣leetcode 432.全O(1)的数据结构

简介: golang力扣leetcode 432.全O(1)的数据结构

432.全O(1)的数据结构

432.全O(1)的数据结构

题解

双向链表+哈希表(哈希表nodes 维护每个字符串当前所处的链表节点)

代码

package main
import "container/list"
type node struct {
  keys  map[string]struct{}
  count int
}
type AllOne struct {
  *list.List
  nodes map[string]*list.Element
}
func Constructor() AllOne {
  return AllOne{
    List:  list.New(),
    nodes: make(map[string]*list.Element),
  }
}
func (l *AllOne) Inc(key string) {
  if cur := l.nodes[key]; cur != nil { //在链表中
    curNode := cur.Value.(node)
    //如果新的key的count不等于下一个的count,则在当前cur后插入一个新的
    if nxt := cur.Next(); nxt == nil || nxt.Value.(node).count > curNode.count+1 {
      l.nodes[key] = l.InsertAfter(node{
        keys:  map[string]struct{}{key: {}},
        count: curNode.count + 1,
      }, cur)
    } else { //下一个节点存在并且count刚好等于新的count
      nxt.Value.(node).keys[key] = struct{}{}
      l.nodes[key] = nxt
    }
    //将key从其所在的节点上删除
    delete(curNode.keys, key)
    if len(curNode.keys) == 0 { //如果没有key就移除这个节点
      l.Remove(cur)
    }
  } else { //不在链表中
    if l.Front() == nil || l.Front().Value.(node).count > 1 { //如果没有头节点,或者头节点的count大于0,则直接插入一个新的
      l.nodes[key] = l.PushFront(
        node{
          map[string]struct{}{key: {}},
          1,
        })
    } else { //如果有头节点,并且头节点的count=1,则插入头节点的keys中
      l.Front().Value.(node).keys[key] = struct{}{}
      l.nodes[key] = l.Front()
    }
  }
}
func (l *AllOne) Dec(key string) {
  cur := l.nodes[key]
  curNode := cur.Value.(node)
  if curNode.count > 1 {
    //如果前一个节点不存在,或则前一个节点的count小于新的count,则直接在前一个结点的后面插入一个新的节点
    if pre := cur.Prev(); pre == nil || pre.Value.(node).count < curNode.count-1 {
      l.nodes[key] = l.InsertBefore(node{
        keys:  map[string]struct{}{key: {}},
        count: curNode.count - 1,
      }, cur)
    } else { //前一个节点存在并且前一个节点的count等于新count
      pre.Value.(node).keys[key] = struct{}{}
      l.nodes[key] = pre
    }
  } else { //说明key只出现过一次,直接移除即可
    delete(l.nodes, key)
  }
  //将key从其所在的节点上删除
  delete(curNode.keys, key)
  //如果这个节点上一个key都没有,则将节点删除
  if len(curNode.keys) == 0 {
    l.Remove(cur)
  }
}
func (l *AllOne) GetMaxKey() string {
  if b := l.Back(); b != nil {
    for key := range b.Value.(node).keys {
      return key
    }
  }
  return ""
}
func (l *AllOne) GetMinKey() string {
  if f := l.Front(); f != nil {
    for key := range f.Value.(node).keys {
      return key
    }
  }
  return ""
}
/**
 * Your AllOne object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Inc(key);
 * obj.Dec(key);
 * param_3 := obj.GetMaxKey();
 * param_4 := obj.GetMinKey();
 */
目录
相关文章
|
2月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
2月前
|
索引
力扣(LeetCode)数据结构练习题(3)------链表
力扣(LeetCode)数据结构练习题(3)------链表
101 0
|
2月前
力扣(LeetCode)数据结构练习题(2)
力扣(LeetCode)数据结构练习题(2)
33 0
|
2月前
|
存储
力扣(LeetCode)数据结构练习题
力扣(LeetCode)数据结构练习题
61 0
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
224 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
37 1
|
1月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
56 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
52 4