数据结构与算法:栈和队列的python(deque)实现(附有leetcode题20、1047、150逆兰波表达式、347前k个高频元素题解)

在python中用deque双向队列来表示栈或队列。或者用list来表示栈。

deque双向队列

常用函数如下:

python 复制代码
from collections import deque

# 创建一个空的deque
d = deque()

# 创建一个包含元素的deque
d = deque([1, 2, 3])

# 在deque的右侧添加一个元素
d.append(4)

# 在deque的左侧添加一个元素
d.appendleft(0)

# 从deque的右侧移除并返回一个元素
d.pop()

# 从deque的左侧移除并返回一个元素
d.popleft()

# 扩展deque的右侧,通过添加iterable中的元素
d.extend([5, 6, 7])

# 扩展deque的左侧,通过添加iterable中的元素
d.extendleft([7, 6, 5])

# 向右旋转deque n步
d.rotate(2)

# 向左旋转deque n步
d.rotate(-2)

# 移除所有元素,使deque为空
d.clear()

# 返回deque中元素等于x的数量
d.count(1)

# 返回deque中第一个x元素的索引
d.index(2)

# 反转deque中的元素
d.reverse()

# 移除deque中第一个出现的value
d.remove(3)

# 获取指定索引的元素,支持负索引
first_element = d[0]  # 获取第一个元素
last_element = d[-1]  # 获取最后一个元素

# 设置指定索引的元素
d[0] = 100

# 删除指定索引的元素
del d[0]

leetcode20.有效的括号

python 复制代码
class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        stack = deque()
        bracket_map = {')': '(', '}': '{', ']': '['}
        for char in s:
            # 当前遍历到右括号
            if char in bracket_map:
                # 栈不为空且栈顶元素与当前右括号匹配
                if stack and stack[-1] == bracket_map[char]:
                    stack.pop()
                else:
                # 栈为空或不匹配 
                    return False
            # 当前遍历到左括号
            else:
                stack.append(char)
        # 如果栈为空,说明所有括号都正确匹配
        return not stack

效率:12ms,击败85.70%

leetcode1047.删除字符串中的所有相邻重复项

python 复制代码
class Solution(object):
    def removeDuplicates(self, s):
        """
        :type s: str
        :rtype: str
        """
        stack = deque()
        for char in s:
            # 如果栈不为空且栈顶元素匹配
            if stack and stack[-1] == char:
                stack.pop()
            else:
                stack.append(char)
        return ''.join(stack)

效率:90ms,击败14.25%,需要优化

优化

可以看到,如上版本的时间复杂度依旧是O(n),因为遍历一遍字符串需要O(n),然后加上额外的常数操作(弹出或加入元素),所以总体还是O(n)。如果想要优化的话,只能从数据结构的存储来优化,即舍弃栈,改为list。

python 复制代码
class Solution(object):
    def removeDuplicates(self, s):
        """
        :type s: str
        :rtype: str
        """
        stack = list()
        for char in s:
            # 如果栈不为空且栈顶元素匹配
            if stack and stack[-1] == char:
                stack.pop(-1)
            else:
                stack.append(char)
        return ''.join(stack)

55ms,击败68.83%

leetcode150.逆兰波表达式

注意使用lambda表达式简化if判断。

注意入栈时用int包裹,因为是字符串 。

而且python3对于除法是向0取整。而python2对于除法是向负无穷取整。所以python2的需要判断x和y是否同号,同号的话,需要计算x和y绝对值的除法再取反。

python(python2)

python 复制代码
class Solution(object):
    def evalRPN(self, tokens):
        """
        :type tokens: List[str]
        :rtype: int
        """
        ops = {'+': lambda x, y: x + y, '-': lambda x, y: x - y, '*': lambda x, y: x * y, '/': lambda x, y: x / y if x * y > 0 else -(abs(x) / abs(y))}
        stack = deque()
        for token in tokens:
            if token in ops:
                y = stack.pop()
                x = stack.pop()
                res = ops[token](x, y)
                # print("当前操作符:{}, 当前x:{}, 当前y:{}, 结果:{}".format(token, x, y, res))
                stack.append(res)
            else:
                stack.append(int(token))
        return stack.pop()

效率:25ms,击败70.08%

python3

python3 复制代码
class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        ops = {'+': lambda x, y: x + y, '-': lambda x, y: x - y, '*': lambda x, y: x * y, '/': lambda x, y: int(x / y)} # 注意除法后得到的是int
        stack = deque()
        for token in tokens:
            if token in ops:
                y = stack.pop()
                x = stack.pop()
                # print(f"当前操作符:{token}, 当前y:{y}, 当前x:{x}")
                stack.append(ops[token](x, y))
            else:
                stack.append(int(token))
        return stack.pop()

效率:40ms,击败76.51%

leetcode347.前k个高频元素

代码1:map+自定义排序

最先想到的是map(在python中的数据结构是dict)+自定义排序解决,如下

python 复制代码
class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        m = dict()
        for num in nums:
            m[num] = m.get(num, 0)+1
        to_sort_list = [(key, val) for key,val in m.items()]
        sorted_list = sorted(to_sort_list, key=lambda item:item[1], reverse=True)
        top_k_keys = [item[0] for item in sorted_list[:k]]
        return top_k_keys

效率:34ms,击败20.00%。需要优化。

代码2:小顶堆

代码1的时间复杂度为O(nlogn),主要来自于对整个list进行排序。但是我们只取前k大,所以其实只用找出前k大的元素即可,不用对整个list排序。为此想到元素为k个的小顶堆,或者说优先队列。这样时间复杂度是O(nlog k),当k远小于n时,优化明显。

python 复制代码
class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        # 使用 Counter 计算每个数字的频率
        counter = Counter(nums)
        # 使用 heapq.nlargest 来找到频率最高的 k 个元素
        # 这里我们使用一个 lambda 函数作为 key,以便 heapq.nlargest 可以根据频率排序
        top_k = heapq.nlargest(k, counter.items(), key=lambda item: item[1])
        # 提取 top_k 中的元素(即数字本身)
        return [item[0] for item in top_k]

效率:26ms,击败62.51%。还行,主要是代码简洁。

相关推荐
天天要nx21 分钟前
D24【 python 接口自动化学习】- python 基础之判断与循环
python
攻城狮7号25 分钟前
【4.5】图搜索算法-BFS和DFS求岛屿的最大面积
c++·算法·深度优先·宽度优先·图搜索算法
攻城狮7号28 分钟前
【4.6】图搜索算法-DFS和BFS解合并二叉树
c++·算法·深度优先·宽度优先·图搜索算法
deflag30 分钟前
第T2周:TensorFlow实现彩色图片分类(CIFAR10数据集),并实现自己的真实图片分类
python·机器学习·分类·tensorflow
wypdao4 小时前
探索后量子安全:基于格加密技术的未来密码学展望
算法·安全·密码学·量子计算
雷达学弱狗6 小时前
波动方程(将麦克斯韦方程组求出只有E或H的表达式)
线性代数·算法·机器学习
不知名舍友6 小时前
C++:采用模板封装顺序表,栈,队列
开发语言·c++·算法
m0_571957587 小时前
Java | Leetcode Java题解之第441题排列硬币
java·leetcode·题解
python1567 小时前
Python Pandas数据处理效率提升指南
开发语言·python·pandas