刷题最常用的数据结构详解:集合(set)、栈(stack)、队列(deque\queue)、哈希表(hashmap)、堆(heap)

在力扣刷题时,除了最基础的列表(数组)、字符串操作,经常会用到 集合、栈、队列(双向队列)、哈希表、堆 这五种数据结构进行辅助解题,下面是这些数据结构的原理特性详解,以及python里面的用法。

各数据结构方法 时间复杂度 一栏:
https://blog.csdn.net/weixin_44414948/article/details/113934407

1、集合(set)

原理:就是数学课里面学的集合概念,有合集、并集、差集的那个,构成就不再赘述了。。。

特性

1、无序性
2、确定性(编程时表现为不允许下标访问,以及修改元素)
3、不重复性(常用于列表去重)

python实现

# 定义
s = set()

# 增,用法类似于list.append()
s.add()

# 删
s.pop(1)  # 删除指定索引的元素,不传参则随机删除一个
s.remove(x)  # 删除指定值的元素,必须传参
s.clear()  # 清空set
s.discard()  # 和remove类似,不传参不会报错

# 改
# 和字符串一样,不允许中途修改元素的操作,不支持下标索引的方式
s[0] # 这类的操作是不允许的

# 查
for s_i in s: # 使用for in 形式遍历,下标的遍历不允许

# 逻辑运算
s1 & s2  # 求两集合的交集
s1 | s2  # 求两集合的并集
s1 - s2  # 求两集合的差集

用法:列表去重

A = [1, 3, 2, 3, 2, 4, 5, 6]
A = set(A)
print(A)  # 结果为去重后的A,即[1, 3, 2, 4, 5, 6],顺序随机

举例:

力扣刷题:448.找到所有数组中消失的数字(集合差法)
https://blog.csdn.net/weixin_44414948/article/details/113803271

2、栈(stack)

在这里插入图片描述
原理:
栈本质上就是一个容器,存放元素,和列表很像。

特性:
先入后出,后入先出(和队列相反)

python实现:
由于栈和列表很像,所以刷题时可以使用 list 当做 栈 使用,使用 pop() 方法实现出栈,append() 方法实现入栈,熟练这些刷题就够用了。

# 定义
stack = [1, 2, 3, 4]

# 入栈
stack.append(5)

# 出栈
stack.pop() # 默认删除最后一个元素,即最后入栈的 5

举例:

力扣刷题:20.有效的括号(利用栈进行配对)
https://blog.csdn.net/weixin_44414948/article/details/114088834

3、队列(deque\queue)

原理:
类似于现实生活中的排队,其元素可以看做是一个个排着队的人。

特性:
先入先出,后入后出(双端队列两边都可以入、出)

python实现:
一般刷题都是使用 collections 库里面的双端队列 deque ,掌握入队、出队操作即可。

import collections
# 定义
queue = collections.deque()

# 入队
queue.append(1)  # 在队列右侧加入
queue.appendleft(2)  # 在队列左侧加入

# 出队
queue.pop()  # 右侧出队
queue.popleft()  # 左侧出队

举例:

1、力扣刷题:101、对称二叉树(队列queue)
https://blog.csdn.net/weixin_44414948/article/details/113748957
2、力扣刷题:剑指 Offer 32 - III. 从上到下打印二叉树 III(单纯的列表、队列queue)
https://blog.csdn.net/weixin_44414948/article/details/113783424

4、哈希表(hashmap)

原理:
根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。就是python里面的字典 dict 。

特性:
可以通过键值对来进行查找,查找速度快,效率高。

python实现:
python自带的 dict 基本数据类型就是 哈希表 , 刷题时一般不使用自带的 dict(),而是使用 collections.defaultdict(), 主要是因为该库字典类型允许在不存在的键添加元素,以下是该字典的基本操作方法。

defaultdict 的真正意义实现一种全局的初始化,访问任何键都不会抛 KeyError 的异常;
defaultdict(int):初始化为 0
defaultdict(float):初始化为 0.0
defaultdict(str):初始化为 ‘’
defaultdict(list):初始化为[],list这种刷题时最常用的

# 定义
import collections

s = [('yellow',1),('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = collections.defaultdict(list)
for k, v in s:
    d[k].append(v)  #将【值v】加入进【字典d】的【键k】中
a=sorted(d.items()) #排序
print(a)

举例:

1、力扣刷题:697.数组的度(哈希表经典题)
https://blog.csdn.net/weixin_44414948/article/details/113881244
2、力扣刷题:1128. 等价多米诺骨牌对的数量(哈希表+排列组合)
https://blog.csdn.net/weixin_44414948/article/details/113177535

5、堆(heap)

原理:
栈是一种具有后进先出的数据结构,堆是一种经过排序的树形数据结构,每个节点都有一个值。

特性:
堆的特点是根节点的值最小(或最大),且根节点的两个树也是一个堆。由于堆的这个特性,常用来实现优先队列。

对于我们刷题的人来说,只需要知道 堆 是可以自己自动排序的数据结构即可,内置的 add 和 pop 方法有兴趣的同学可以看看最下面的拓展知识。

python实现:
刷题只需要熟悉 堆 的特性,会使用python的 堆 定义、添加、删除即可。
使用python的 heapq 库来定义 堆。

import heapq
# 将列表转为堆
L1 = [4, 5, 1, 6, 2, 7, 3, 8]
heapq.heapify(L1)

# 堆添加元素
h = []
heapq.heappush(h, 6)  # 注意此处 h 为列表

# 堆删除最小元素,即最上面的元素
L1 = [4, 5, 1, 6, 2, 7, 3, 8]
heapq.heapify(L1)
heapq.heappop(L1)

举例:

力扣刷题:5638. 吃苹果的最大数目(堆,这题不用 堆 贼难)
https://blog.csdn.net/weixin_44414948/article/details/111824441

以下为堆的拓展知识:

——————————————————————————————————
堆添加元素并自动排序的步骤如下图所示,目标是在堆中找到新元素的合适位置,并且将其插入。步骤如下:

(1)首先在堆的底部插入该元素,在数组实现中,这是数组中当前最后一个元素之后的位置
——————————————————————————————————
(2)然后,进入一个循环,只要新元素的值小于其父节点的值,循环就让这个新元素沿着堆向上“走”,将新的元素和其父节点交换。当这个过程停止的时候(要么新的元素大于或等于其父节点,要么到达了顶部的节点),新的元素就位于其适当的位置。

在这里插入图片描述
内置添加元素 add() 的代码如下:

    def add(self, item):
        self._size += 1
        self._heap.append(item)
        curPos = len(self._heap) - 1
        while curPos > 0:
            parent = (curPos - 1) // 2
            parentItem = self._heap[parent]
            if parentItem <= item:
                break
            else:
                self._heap[curPos] = self._heap[parent]
                self._heap[parent] = item
                curPos = parent

删除操作pop:
删除的目标是在删除根节点之后,返回该节点中的元素,并且调整其他节点的位置以维护堆属性。下面是删除操作的策略:

(1)首先,保存堆中的顶部元素和底部元素的指针,并且将该元素从堆的底部移动到顶部
——————————————————————————————————
(2)从堆的顶部往下走,将最小的元素向上移动一层,直到到达堆的底部

在这里插入图片描述
内置添加元素 pop() 的代码如下:

    def pop(self):
        if self.isEmpty():
            raise Exception("Heap is empty")
        self._size -= 1
        topItem = self._heap[0]
        bottomItem = self._heap.pop(len(self._heap) - 1)
        if len(self._heap) == 0:
            return bottomItem
           
        self._heap[0] = bottomItem
        lastIndex = len(self._heap) - 1
        curPos = 0
        while True:
            leftChild = 2 * curPos + 1 
            rightChild = 2 * curPos + 2
            if leftChild > lastIndex:
                break
            if rightChild > lastIndex:
                maxChild = leftChild;
            else:
                leftItem  = self._heap[leftChild]
                rightItem = self._heap[rightChild]
                if leftItem < rightItem:
                    maxChild = leftChild
                else:
                    maxChild = rightChild
            maxItem = self._heap[maxChild]
            if bottomItem <= maxItem:
                break
            else:
                self._heap[curPos] = self._heap[maxChild]
                self._heap[maxChild] = bottomItem
                curPos = maxChild
        return topItem

拓展知识参考来源:https://blog.csdn.net/dta0502/article/details/80834787

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值