算法-数据结构

算法-数据结构

金无足赤人无完人,在处理实际问题的时候我们可以使用到很多合适的数据结构,但目前还没有一个数据结构可以称的上完美。查询速度快的,插入的速度就会慢;插入速度和查询速度都快得,占用的空间就会多;占用空间少的,可能会牺牲查询或插入的速度。
所以我们要在不同的问题使用合适的数据结构,就像大家在找对象的时候,他/她不一定是最完美的,但一定是适合你的,希望大家都能找到合适的对象~

146. LRU 缓存

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
分析
  1. 函数 getput 必须以 O(1) 的平均时间复杂度运行。
  2. 能支持 get O(1) 的有哈希表、数组,支持 put O(1) 的有可变数组的末尾元素、哈希表、双向链表
  3. 因为put的对象需要是最不长使用的数据,没有要确保最不长使用的数据快速被找的,所以使用的是链表,链表可以快速更新节点位置
class DLinkNode():
    def __init__(self, key=0, val=0):
        self.key = key
        self.val = val
        self.next = None
        self.prev = None

class LRUCache:

    def __init__(self, capacity: int):
        self.size = 0
        self.capacity = capacity
        self.head = DLinkNode()
        self.tail = DLinkNode()
        # 虚拟头节点,尾节点
        self.head.next = self.tail
        self.tail.prev = self.head
        self.cache = dict()

    def get(self, key: int) -> int:
        if key in self.cache:
            node = self.cache[key]
            # 更新头节点
            self.remove_node(node)
            self.add_to_head(node)
            return node.val
        else:
            return -1

    def put(self, key: int, value: int) -> None:
        if key in self.cache:
            node = self.cache[key]
            node.val = value
            self.remove_node(node)
            self.add_to_head(node)
        else:
            node = DLinkNode(key, value)
            self.add_to_head(node)
            self.cache[key] = node
            self.size += 1
            if self.size > self.capacity:
                self.del_tail_node()
                self.size -= 1
    # 删除节点 O(1)
    def remove_node(self, node):
        node.next.prev = node.prev
        node.prev.next = node.next
    
    # 更新头节点
    def add_to_head(self, node):
        node.next = self.head.next
        self.head.next = node
        node.prev = self.head
        node.next.prev = node
    # 删除尾节点
    def del_tail_node(self):
        node = self.tail.prev
        self.tail.prev = node.prev
        self.tail.prev.next = self.tail
        self.cache.pop(node.key)


# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)

155. 最小栈

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

分析

  1. push pop top可通过变长数组完成
  2. getMin() 是关键, 我们可以通过另一个变长数组记录当前的最小值
    • 记录数组a=[4,5,6,2,3,1]
    • 最小值数组b=[4,4,4,2,2,1]
    • 差值记录a=[0,1,2,-2,1,-1]:前一个最小值可以通过当前最小值减去记录数组的值:1-(-1)= 2;2-(-2)= 4。具体可看代码
class MinStack:

    def __init__(self):
        # 记录差值
        self.stack = []
        # 记录最小值
        self.min_: int

    def push(self, val: int) -> None:
        if not self.stack:
            # 差值为0,最小值为val
            self.stack.append(0)
            self.min_ = val
        else:
            diff = val - self.min_
            self.stack.append(diff)
            # 差值小于零,更新最小值
            if diff < 0:
                self.min_ = val
    def pop(self) -> None:
        pop_ = self.stack.pop()
        # 说明是最小值
        if pop_ < 0:
            ret = self.min_
            self.min_ += -pop_
            return ret
        else:
            return self.min_ + pop_


    def top(self) -> int:
        if self.stack[-1] <= 0:
            return self.min_
        else:
            return self.min_ + self.stack[-1]

    def getMin(self) -> int:
        return self.min_

380. O(1) 时间插入、删除和获取随机元素

实现RandomizedSet 类:

  • RandomizedSet() 初始化 RandomizedSet 对象
  • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false
  • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false
  • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。

你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O(1)

  1. insert remove 可通过哈希表,变成数组末尾、链表末尾实现
  2. getRandom() 只能通过数组实现,因为数组可以直接取数且任意一个元素出现概率是相等的

用哈希表记录元素下标,删除时将删除元素与末尾元素交换,这样就相对于删除末尾元素了

class RandomizedSet:

    def __init__(self):
        self.arr = []
        self.dic = dict()


    def insert(self, val: int) -> bool:
        if val in self.dic:
            return False
        idx = len(self.arr)
        self.dic[val] = idx
        self.arr.append(val)

        return True
    def remove(self, val: int) -> bool:
        if val not in self.dic:
            return False
        idx = self.dic[val]
        self.arr[idx] = self.arr[-1]
        self.dic[self.arr[idx]] = idx
        self.arr.pop()
        self.dic.pop(val)
        return True

    def getRandom(self) -> int:
        return choice(self.arr)

2671. 频率跟踪器

211. 添加与搜索单词 - 数据结构设计

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值