Leetcode学习笔记 队列和栈

队列和栈-18/18

队列-1
设计循环队列,中等

class MyCircularQueue:

    def __init__(self, k: int):
        """
        Initialize your data structure here. Set the size of the queue to be k.
        """
        self.queue = [0]*k
        self.headIndex = 0
        self.count = 0 #这个属性至关重要
        self.capacity = k
        

    def enQueue(self, value: int) -> bool:
        """
        Insert an element into the circular queue. Return true if the operation is successful.
        """
        if self.count == self.capacity:
            return False
        self.queue[(self.headIndex + self.count) % self.capacity] = value
        self.count +=1
        return True

    def deQueue(self) -> bool:
        """
        Delete an element from the circular queue. Return true if the operation is successful.
        """
        if self.count == 0:
            return False
        self.headIndex = (self.headIndex + 1) % self.capacity
        self.count -= 1
        return True

    def Front(self) -> int:
        """
        Get the front item from the queue.
        """
        if self.count == 0:
            return -1
        return self.queue[self.headIndex]
        

    def Rear(self) -> int:
        """
        Get the last item from the queue.
        """
        if self.count == 0:
            return -1
        return self.queue[(self.headIndex + self.count -1) % self.capacity]
        

    def isEmpty(self) -> bool:
        """
        Checks whether the circular queue is empty or not.
        """
        if self.count == 0:
            return True
        return False
        #直接 return self.count == 0 即可

    def isFull(self) -> bool:
        """
        Checks whether the circular queue is full or not.
        """
        return self.count == self.capacity

队列和BFS-3

岛屿数量,中等
用BFS做,代码如下:

  1. 队列可以直接用列表,入队用append,出队用 pop(0)。
  2. 遍历四周位置可以用
for x,y in [(h-1,l),(h,l-1),(h+1,l),(h,l+1)]:
  1. 可以使用双边判断来写区间判定:
if 0 <= x < m and 0 <= y < n and grid[x][y] == "1" :
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        m = len(grid)
        if m == 0: return 0
        n = len(grid[0])
        queue = []
        count = 0
        for i in range(m):
            for j in range(n):
                if grid[i][j]== "1":
                    count += 1
                    grid[i][j] = "0"
                    queue.append((i,j))
                    while queue:
                        temp = queue.pop(0)
                        h,l = temp[0],temp[1]
                        for x,y in [(h-1,l),(h,l-1),(h+1,l),(h,l+1)]:
                            if 0 <= x < m and 0 <= y < n and grid[x][y] == "1" :
                                grid[x][y] = '0'
                                queue.append((x,y))
        return count

打开转盘锁,中等
用BFS,数据结构需要两个 set 和一个 queue
一个 set 用来存deadends, 一个用来存 已经遍历过的 code ,
queue 存 ( code , step )的元组,分别记录遍历到的密码和走到这个密码的最小步数。
代码如下:

class Solution:
    def openLock(self, deadends: List[str], target: str) -> int:
        dead = set(deadends)
        visited = {'0000'}
        queue = [('0000',0)]
        while queue:
            code , step = queue.pop(0)
            if code == target:
                return step
            if code in dead:
                continue
            for i in range(4):
                for j in (-1,1):
                    s = (int(code[i])+j) % 10
                    nextcode = code[:i] + str(s) + code[i+1:]
                    if nextcode not in visited:
                        queue.append((nextcode,step+1))
                        visited.add(nextcode)
        return -1

完全平方数,中等
可以用动态规划做
这里主要训练BFS
以 n 作为根,其子节点为 n 减去平方数序列的余数,如果余数为0,则层数就为最少平方数
代码如下:

class Solution:
    def numSquares(self, n: int) -> int:
        m = int(n**0.5)
        numlst = [i*i for i in range(1,m+1)]
        queue = [(n,0)]
        while queue:
            num,step = queue.pop(0)
            if num == 0:
                return step
            for item in numlst:
                if num - item < 0:
                    break
                else:
                    queue.append((num-item,step+1))

用队列存储,同一层会产生大量的重复元素,比如先减1再减4,和先减4再减1,得到的结果相同,层数深了以后会产生很大的时间消耗。
对此进行优化,每一层的情况用集合来存储,下一层的元素添加到新一层的集合中
代码如下:

class Solution:
    def numSquares(self, n: int) -> int:
        m = int(n**0.5)
        numlst = [i*i for i in range(1,m+1)]
        queue = {n}
        step = 0
        while queue:
            step += 1
            nextqueue = set()
            for reminder in queue:
                for item in numlst:
                    if reminder - item == 0:
                        return step
                    elif reminder < item:
                        break
                    else:
                        nextqueue.add(reminder - item)
            queue = nextqueue

栈-4

最小栈,简单
#无穷大常数:math.inf
维护两个数组,其一为普通栈,其二为最小值栈,存的是当前栈中元素的最小值。

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.min_stack = [math.inf]


    def push(self, x: int) -> None:
        self.stack.append(x)
        self.min_stack.append(min(x,self.min_stack[-1]))

    def pop(self) -> None:
        self.stack.pop()
        self.min_stack.pop()

    def top(self) -> int:
        return self.stack[-1]

    def getMin(self) -> int:
        return self.min_stack[-1]

有效的括号,简单
简单的配对问题,左括号入栈,右括号匹配,将字符串转化为数字便于处理,代码如下:

class Solution:
    def trans(self,a: str) -> int:
        if a == '(':
            return 1
        if a == '[':
            return 2
        if a == '{':
            return 3
        if a == ')':
            return -1
        if a == ']':
            return -2
        if a == '}':
            return -3

    def isValid(self, s: str) -> bool:
        lst = list(s)
        stack = []
        for item in lst:
            temp = self.trans(item)
            if temp > 0:
                stack.append(temp)
            else:
                if not stack:return False #这一句别漏了,否则如果右括号多了会对空栈进行弹出
                left = stack.pop()
                if left + temp != 0:
                    return False
        return not stack

官解使用字典,将左右括号分别作为值和键,缩短了代码:

class Solution:
    def isValid(self, s: str) -> bool:
        if len(s) % 2 == 1:
            return False
        
        pairs = {
            ")": "(",
            "]": "[",
            "}": "{",
        }
        stack = list()
        for ch in s:
            if ch in pairs:
                if not stack or stack[-1] != pairs[ch]:
                    return False
                stack.pop()
            else:
                stack.append(ch)
        
        return not stack

每日温度,中等
单调栈
维护一个单调不增的栈,如果当前温度小于等于栈顶温度,则入栈。
如果新温度大于栈顶温度,则用新日期减栈顶日期,就是栈顶日期的ans值

class Solution:
    def dailyTemperatures(self, T: List[int]) -> List[int]:
        stack = []
        n = len(T)
        ans = [0]*n
        for i in range(n):
            while stack and stack[-1][0] < T[i]:
                ans[stack[-1][1]] = i - stack[-1][1]
                stack.pop()
            stack.append((T[i],i))
        return ans

逆波兰表达式求值,中等
简单
注意:整除运算应该写return int(a/b)

栈和DFS-4

岛屿数量,中等
DFS,用递归做,注意边界

class Solution:
    def dfs(self,grid,x,y,m,n):
        grid[x][y] = '0'
        for a,b in [(x-1,y),(x,y-1),(x+1,y),(x,y+1)]:
            if 0<=a<m and 0<=b<n and grid[a][b] == '1':
                self.dfs(grid,a,b,m,n)

    def numIslands(self, grid: List[List[str]]) -> int:
        m = len(grid)
        if not m:
            return 0
        n = len(grid[0])
        count = 0
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    count += 1
                    self.dfs(grid,i,j,m,n)
        return count

克隆图,中等
无向连通图,输入为第一个节点,用DFS进行克隆,递归调用克隆方法本身

"""
# Definition for a Node.
class Node:
    def __init__(self, val = 0, neighbors = None):
        self.val = val
        self.neighbors = neighbors if neighbors is not None else []
"""

class Solution:
    def __init__(self):
        self.visited = {}
    def cloneGraph(self, node: 'Node') -> 'Node':
        if not node:
            return node
        #递归出口1,节点已经被克隆,直接返回
        if node in self.visited:
            return self.visited[node]
		#递归出口2,节点未被克隆,创建新节点,并创建/查找其邻接节点
        cloned_node = Node(node.val,[])
        self.visited[node] = cloned_node
        for item in node.neighbors:
            cloned_node.neighbors.append(self.cloneGraph(item))
        return cloned_node

目标和,中等
DFS复杂度 O(2^N),超时
不知道为什么放在这一节

class Solution:
    def __init__(self):
        self.count = 0
    def DFS(self,nums,x,Sum,S):
        n = len(nums)
        if x == n:
            if Sum == S:
                self.count += 1
            return
        self.DFS(nums,x+1,Sum+nums[x],S)
        self.DFS(nums,x+1,Sum-nums[x],S)

    def findTargetSumWays(self, nums: List[int], S: int) -> int:
        if not nums and S != 0:
            return 0
        self.DFS(nums,0,0,S)
        return self.count

得用DP:

class Solution:
    def findTargetSumWays(self, nums: List[int], S: int) -> int:
        if not nums:
            if S == 0:return 1
            else: return 0
       	#S的范围需要在-1000到1000
        if S < -1000 or S > 1000:
            return 0
        n = len(nums)
        dp = [[0 for _ in range(2001)] for _ in range(n)]
        dp[0][1000+nums[0]] = 1
        dp[0][1000-nums[0]] += 1
        for i in range(1,n):
            for j in range(2001):
                if dp[i-1][j] > 0:
                    dp[i][j+nums[i]] += dp[i-1][j]
                    dp[i][j-nums[i]] += dp[i-1][j]
        return dp[n-1][S+1000] #这里记得是S+1000

二叉树的中序遍历,中等
简单
递归:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def __init__(self):
        self.ans = []
    def DFS(self,node):
        if not node:
            return
        self.DFS(node.left)
        self.ans.append(node.val)
        self.DFS(node.right)
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root: return root
        self.DFS(root)
        return self.ans

非递归:**

小结-6

用栈实现队列,简单
用两个栈实现:

class MyQueue:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.stack1 = []
        self.stack2 = []
        self.size = 0

    def push(self, x: int) -> None:
        """
        Push element x to the back of queue.
        """
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        self.stack2.append(x)
        while self.stack1:
            self.stack2.append(self.stack1.pop())
        self.size += 1


    def pop(self) -> int:
        """
        Removes the element from in front of queue and returns that element.
        """
        self.size -= 1
        return self.stack2.pop()


    def peek(self) -> int:
        """
        Get the front element.
        """
        if self.stack2:
            return self.stack2[-1]

    def empty(self) -> bool:
        """
        Returns whether the queue is empty.
        """
        return self.size == 0

用队列实现栈,简单
用一个队列即可实现,入队列时,先将当前元素压如队尾,再将其他元素依次从队头弹出压入队尾

class MyStack:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.queue = []
        self.size = 0

    def push(self, x: int) -> None:
        """
        Push element x onto stack.
        """
        self.queue.append(x)
        for _ in range(self.size):
            self.queue.append(self.queue.pop(0))
        self.size += 1

    def pop(self) -> int:
        """
        Removes the element on top of the stack and returns that element.
        """
        self.size -= 1
        return self.queue.pop(0)

    def top(self) -> int:
        """
        Get the top element.
        """
        return self.queue[0]

    def empty(self) -> bool:
        """
        Returns whether the stack is empty.
        """
        return self.size == 0

字符串解码,中等

用栈来对括号进行配对,注意各种边界条件
字符串列表合成一个串:不能用str()强制转化,要用join()

class Solution:
    def decodeString(self, s: str) -> str:
        zhongkuohao = 0
        lst = list(s)
        stack = []
        num = []
        ans = []
        while lst:
            temp = lst.pop()
            if not zhongkuohao:
                if temp != ']':
                    ans.append(temp)
                else:
                    zhongkuohao += 1
                    stack.append(temp)
            else:
                if temp != '[':
                    stack.append(temp)
                    if temp == ']':
                        zhongkuohao += 1
                else:
                    zhongkuohao -= 1
                    lap = ''
                    st = ''
                    num.clear()
                    tempnum = lst.pop()
                    tempalph = stack.pop()
                    while tempalph != ']':
                        lap += tempalph
                        tempalph = stack.pop()#bug2:这句漏了导致有[]的循环一直不结束
                    while '0' <= tempnum <= '9':
                        num.append(tempnum)
                        if lst:
                            tempnum = lst.pop()
                        #bug3:数字开头的输入会死循环,
                        #进行如下修改
                    #if not ('0' <= tempnum <= '9'):
                        #lst.append(tempnum)
                        else:
                            tempnum = ''
                    if tempnum:
                        lst.append(tempnum)
                    n = int(''.join(reversed(num)))
                    for _ in range(n):
                        st += lap
                    lst.append(st)
        ans.reverse()
        #return str(ans)
        #bug1:用str强制转换列表会变成这样"['a', 'b', 'c']"
        return "".join(ans)

图像渲染,简单
简单的DFS,有一点需要注意:
不引入visited 直接修改原矩阵的情况下,
如果 oldColor == newColor,递归会进入死循环爆栈

class Solution:
    def DFS(self,image,x,y,oldColor,newColor):
        m = len(image)
        n = len(image[0])
        if x < 0 or x >= m or y < 0 or y >= n:
            return
        else:
            if image[x][y] == oldColor:
                image[x][y] = newColor
                self.DFS(image,x-1,y,oldColor,newColor)
                self.DFS(image,x+1,y,oldColor,newColor)
                self.DFS(image,x,y-1,oldColor,newColor)
                self.DFS(image,x,y+1,oldColor,newColor)
            return

    def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
        oldColor = image[sr][sc]
        #下面的判断很有必要
        if oldColor == newColor:
            return image
        self.DFS(image,sr,sc,oldColor,newColor)
        return image

01矩阵,中等
用BFS做
思路1:从 1 开始BFS,则每个 1 都需重新BFS一次,复杂度高
思路2:从 0 开始BFS,将所有 0 都设置为原点,从原点向外泛洪,每次泛洪都将答案矩阵标记+1
将答案矩阵的初始值设为-1,则判断是否未负可以保证不会重复添加节点

以下代码用 set 来存每次泛洪的点集,由于不会重复添加节点,也可以使用 list
但是语句queue = nextqueue 应该改为:
queue.clear()
queue.extend(nextqueue)

class Solution:
    def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        if not matrix:return matrix
        if not matrix[0]:return matrix
        queue = set()
        d = [[-1,0],[0,-1],[1,0],[0,1]]
        count = 0
        m,n = len(matrix),len(matrix[0])
        ans = [[-1 for _ in range(n)]for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if matrix[i][j] == 0:
                    ans[i][j] = 0
                    queue.add((i,j))
        while queue:
            count += 1
            nextqueue = set()
            for item in queue:
                for i in range(4):
                    x,y = item[0]+d[i][0],item[1]+d[i][1]
                    if 0 <= x < m and 0 <= y < n and ans[x][y] < 0:
                        nextqueue.add((x,y))
                        ans[x][y] = count
            queue = nextqueue
        return ans

钥匙和房间,中等
简单的BFS

class Solution:
    def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
        n = len(rooms)
        roomset = set()
        for i in range(1,n):
            roomset.add(i)
        queue = [0]
        while queue:
            temp = queue.pop(0)
            keynum = len(rooms[temp])
            for i in range(keynum):
                key = rooms[temp][i]
                if key in roomset:
                    queue.append(key)
                    roomset.remove(key)
        return len(roomset) == 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值