数据结构(Python实现)------队列

数据结构(Python实现)------ 队列

队列

基本概念

在这里插入图片描述

Python实现

基本的队列

class Queue(object):
    def __init__(self):
        self.data = []

    def isEmpty(self):
        return self.data == []

    def insert(self,newElem):
        self.data.append(newElem)

    def delete(self):
        if self.isEmpty():
            raise Exception("Your queue is Empty!")

        else:
            return self.data.pop()

    def head(self):
        return self.data[0]

    def tail(self):
        return self.data[len(self.data)-1]

    def size(self):
        return len(self.data)

双向队列

class DQueue(object):
    def __init__(self):
        self.data = []

    def isEmpty(self):
        return self.data == []

    def insertHead(self,newElem):
        self.data.insert(0,newElem)

    def insertTail(self,newElem):
        self.data.append(newElem)

    def deleteHead(self):
        if self.isEmpty():
            raise Exception("Your Dqueue is empty!")
        else:
            return self.data.pop(0)

    def deleteTail(self):
        if self.isEmpty():
            raise Exception("Ypur DQueue is empty!")
        else:
            return self.data.pop()

    def getHead(self):
        if self.isEmpty():
            raise Exception("Your DQueue is empty!")
        else:
            return self.data[0]

    def getTail(self):
        if self.isEmpty():
            raise Exception("Your DQueue is empty!")
        else:
            return self.data[len(self.data)-1]

    def size(self):
        return len(self.data)

队列与BFS

基本概念

顾名思义,BFS总是先访问完同一层的结点,然后才继续访问下一层结点,它最有用的性质是可以遍历一次就生成中心结点到所遍历结点的最短路径,这一点在求无权图的最短路径时非常有用。

Python实现

基本的队列与BFS

关键步骤:

  1. 创建一个队列,遍历的起始点放入队列

  2. 从队列中取出一个元素,打印它,并将其未访问过的子结点放到队列中

  3. 重复2,直至队列空

 class Queue(object):
    def __init__(self):
        self.data = []

    def isEmpty(self):
        return self.data == []

    def enQueue(self,newElwm):
        self.data.append(newElwm)

    def deQueue(self):
        if self.isEmpty():
            raise Exception("Ypur Queue is Empty!")
        else:
            return self.data.pop(0)

    def gethead(self):
        if self.isEmpty():
            raise Exception("Your Queue is Empty!")
        else:
            return self.data[0]

    def getTail(self):
        if self.isEmpty():
            raise Exception("Your Queue is Empty!")
        else:
            return self.data[len(self.data)-1]

    def size(self):
        return len(self.data)

def bfs(adj,start):
    visited = set()
    q = Queue()
    q.enQueue(start) # 起始点入队
    while q.isEmpty() != True:
        u = q.deQueue()
        print(u)
        for v in adj.get(u,[]):
            if v not in visited:
                visited.add(v)
                q.enQueue(v)



if __name__ == "__main__":
    graph = {1: [4, 2], 2: [3, 4], 3: [4], 4: [5]}

    bfs(graph, 1)


打开转盘锁

在这里插入图片描述
示例 1:

输入:deadends = ["0201","0101","0102","1212","2002"], target = "0202"
输出:6
解释:
可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。
注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的,
因为当拨动到 "0102" 时这个锁就会被锁定。

示例 2:

输入: deadends = ["8888"], target = "0009"
输出:1
解释:
把最后一位反向旋转一次即可 "0000" -> "0009"。

示例 3:

输入: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"
输出:-1
解释:
无法旋转到目标数字且不被锁定。

提示:

死亡列表 deadends 的长度范围为 [1, 500]。
目标数字 target 不会在 deadends 之中。
每个 deadends 和 target 中的字符串的数字会在 10,000 个可能的情况 ‘0000’ 到 ‘9999’ 中产生。

from collections import deque
class Solution(object):
    def openLock(self, deadends, target):
        """
        :type deadends: List[str]
        :type target: str
        :rtype: int
        """
        deadends = set(deadends)
        if "0000" in deadends: #如果连起点都不能走就88
            return -1
        
        queue = deque()
        queue.append(["0000", 0])
        cnt = 0
 
        while queue:
            node, cnt = queue.popleft() #取一个点出来,cnt是当前走的步数
            if node == target: #找到了
                return cnt     
 
            for i in range(4):
                for j in [1, -1]:
                    next_node = node[:i] + str((int(node[i]) + j) % 10) + node[i + 1:] 
 
                    if next_node not in deadends: #新的点可以走而且没走过
                        deadends.add(next_node) #避免重复
                        queue.append([next_node, cnt + 1])
 
        return -1

完全平方数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例 1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.

示例 2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.
方法一:广度优先遍历(图的最短路径)

在这里插入图片描述
举例说明方法:

1、例如对于上图中的13,我们要前往0,我们的第一步有两种走法,先走12和先走9。所以我们需要建立一个队列或者栈,然后将第一步的走法压入队列或者栈中。如下(使用队列, 我们同时记录走的步数)

(12,1),(9,1),(4,1)

2、我们将12出队,然后看12的下一步怎么走,发现能走11,8,3,所以我们将
(11, 2),(8, 2),(3,2)入队。结果如下:
(9,1),(4,1),(11,2),(8,2),(3,2)

3、我们将9出队,然后看9的下一步怎么走,发现能走5,8,0,由于8之前已经访问过,即使现在走8,步数也不会比之前少,所以我们将(5, 2)入队。 当访问0时,我们发现已经到达了0,那么我们更新step+1,然后出循环即可。以下是代码的全部过程:

class Queue(object):
    def __init__(self):
        self.data = []

    def isEmpty(self):
        return self.data == []

    def enQueue(self,newElem):

        self.data.append(newElem)

    def deQueue(self):
        if self.isEmpty():
            raise Exception("Your Queue is Empty!")
        else:
            return self.data.pop(0)

    def getHead(self):
        if self.isEmpty():
            raise Exception("Your Queue is Empty!")
        else:
            return self.data[0]

    def getTail(self):
        if self.isEmpty():
            raise Exception("Your Queue is Empty!")
        else:
            return self.data[-1]

    def size(self):
        return len(self.data)

class Solution:
    def numSquares(self,n):
        """
        :type n: int
        :rtype: int
        """
        q = Queue()
        q.enQueue([n,0])

        visited = [False for _ in range(n+1)]
        visited[n] = True

        while (q.isEmpty() != True):
            num,step = q.deQueue()

            i = 1
            tNum = num - i**2
            while tNum >= 0:
                if tNum == 0:
                    return  step + 1

                if not visited[tNum]:
                    q.enQueue((tNum,step+1))
                    visited[tNum] = True

                i += 1
                tNum = num -i**2



if __name__ == "__main__":
    solu = Solution()

    print(solu.numSquares(12))
方法二:动态规划

动态规划:
通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。
思路:
我们要知道12最少有多少个数构成,实际上如果我们走了一步的话,我们需要知道11、8、3对应的步数,如果我们不走,我们就需要知道12的步数,我们只要通过比较是走0步小,还是走1步哪个更小即可。通过一个式子(转移方程)表示就是

num[n] = min(num[n], num[n-i**2] + 1)
class Solution:
    _dp = [0]
    def numSquares(self, n):
        dp = self._dp
        while len(dp) <= n:
            dp += list((min(dp[-i*i] for i in range(1, int(len(dp)**0.5+1))) + 1,))
        return dp[n]

队列与栈

Python实现

用栈实现队列

使用栈实现队列的下列操作:

push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。

示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false
class Stack(object):
    def __init__(self):
        self.data = []

    def isEmpty(self):
        return self.data ==[]

    def push(self,newElem):
        self.data.append(newElem)


    def pop(self):
        if self.isEmpty():
            raise Exception("Your Stack is Empty!")

        else:
            return self.data.pop()

    def peek(self):
        if self.isEmpty():
            raise Exception("Your Stack is Empty!")

        else:
            return self.data[-1]

    def size(self):
        return len(self.data)


class MyQueue(object):
    def __init__(self):
        self.pushStack = Stack()
        self.popStack = Stack()

    def isEmpty(self):
        if self.pushStack.isEmpty() and self.popStack.isEmpty():
            return True
        else:
            return False

    def push(self,newElem):
        self.pushStack.push(newElem)

    def pop(self):
        while(self.pushStack.isEmpty() != True):
            self.popStack.push(self.pushStack.pop())

        return self.popStack.pop()

    def peek(self):
        if self.isEmpty():
            raise Exception("Your Queue is Empty!")
        else:
            while (self.pushStack.isEmpty() != True):
                self.popStack.push(self.pushStack.pop())

            return self.popStack.peek()



if __name__ == "__main__":

    mq = MyQueue()

    mq.push(1)
    mq.push(2)
    mq.push(3)
    mq.push(4)
    print(mq.pop())
    print(mq.peek())


字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例:

s = "3[a]2[bc]", 返回 "aaabcbc".
s = "3[a2[c]]", 返回 "accaccacc".
s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
class Stack(object):
    def __init__(self):
        self.data =[]

    def isEmpty(self):
        return self.data == []


    def push(self,newElem):
        self.data.append(newElem)

    def pop(self):
        if self.isEmpty():
            raise Exception("Your Stack is Empty!")
        else:
            return self.data.pop()

    def size(self):
        return len(self.data)


class Solution(object):
    def decodeString(self,s):
        stack = Stack()

        curNum = 0
        curString = ''

        for c in s:
            if c == '[':
                stack.push(curString)
                stack.push(curNum)
                curNum = 0
                curString = ''
            elif c == ']':
                num = stack.pop()
                preString = stack.pop()
                curString = preString + num * curString

            elif c.isdigit():
                curNum = curNum * 10 +int(c)

            else:
                curString += c

        return curString


if __name__ == "__main__":
    solu =Solution()
    s = "3[a]2[bc]"
    print(solu.decodeString(s))

图像渲染

有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。

给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。

为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。

最后返回经过上色渲染后的图像。

示例 1:

输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。

注意:

image 和 image[0] 的长度在范围 [1, 50] 内。
给出的初始点将满足 0 <= sr < image.length 和 0 <= sc < image[0].length。
image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535]内。

思路:

从image[sr][sc]出发, BFS找所有跟它颜色一样的点,染成newColor即可,用visited矩阵避免重复。

from collections import deque
class Solution(object):
    def floodFill(self,image,sr,sc,newColor):
        m,n = len(image),len(image[0])
        color = image[sr][sc]
        image[sr][sc] = newColor

        visited = [[0 for _ in range(n+1)] for _ in range(m+1)]

        dx = [1,-1,0,0]
        dy = [0,0,1,-1]

        q = deque()
        q.append([sr,sc])
        while q:
            x0,y0 = q.popleft()
            for k in range(4):
                x = x0 + dx[k]
                y = y0 + dy[k]

                if 0 <= x < m and 0 <= y < n and image[x][y] == color and visited[x][y] == 0:
                    image[x][y] = newColor
                    visited[x][y] = 1
                    q.append([x, y])


        return image
    

01矩阵

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。

示例 1:
输入:

0 0 0
0 1 0
0 0 0

输出:

0 0 0
0 1 0
0 0 0

示例 2:
输入:

0 0 0
0 1 0
1 1 1

输出:

0 0 0
0 1 0
1 2 1

注意:

给定矩阵的元素个数不超过 10000。
给定矩阵中至少有一个元素是 0。
矩阵中的元素只在四个方向上相邻: 上、下、左、右。

思路:
这道题给了我们一个只有0和1的矩阵,让我们求每一个1到离其最近的0的距离,其实也就是求一个距离场,而求距离场那么BFS将是不二之选。

from collections import deque
class Solution(object):
    def updateMatrix(self,matrix):
        if not matrix or not matrix[0]:
            return matrix

        m,n = len(matrix),len(matrix[0])
        res = matrix[:]

        q = deque()

        for i in range(m):
            for j in range(n):
                if matrix[i][j] == 0:
                    q.append([i,j],0)
        dx = [1,-1,0,0]
        dy = [0,0,1,-1]

        visited = [[0 for _ in range(n+1)] for _ in range(m+1)]

        while q:
            tmp,distance = q.popleft()
            x0,y0 = tmp[0],tmp[1]
            
            if matrix[x0][y0] == 1:
                res[x0][y0] = distance
                
            for k in range(4):
                x = x0 + dx[k]
                y = y0 + dy[k]
                
                if 0 <= x < m and 0 <= y <n and visited[x][y] != 1:
                    q.append([[x,y],distance+1])
                    visited[x][y] = 1
                    
        return res

钥匙和房间

有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,…,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。

在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i],每个钥匙 rooms[i][j] 由 [0,1,…,N-1] 中的一个整数表示,其中 N = rooms.length。 钥匙 rooms[i][j] = v 可以打开编号为 v 的房间。

最初,除 0 号房间外的其余所有房间都被锁住。

你可以自由地在房间之间来回走动。

如果能进入每个房间返回 true,否则返回 false。

示例 1:

输入: [[1],[2],[3],[]]
输出: true
解释:  
我们从 0 号房间开始,拿到钥匙 1。
之后我们去 1 号房间,拿到钥匙 2。
然后我们去 2 号房间,拿到钥匙 3。
最后我们去了 3 号房间。
由于我们能够进入每个房间,我们返回 true。

示例 2:

输入:[[1,3],[3,0,1],[2],[0]]
输出:false
解释:我们不能进入 2 号房间。

提示:

1 <= rooms.length <= 1000
0 <= rooms[i].length <= 1000
所有房间中的钥匙数量总计不超过 3000。

思路:
1、初始化时进到第0个房间,拿到所有的钥匙,放在queue里,rooms[0]置为False

2、进到queue里所有的房间,进过的房间都出queue, 拿到所有进过的房间里面的钥匙再存入queue,将该房间设为False,代表已经进去过,下次再拿到该房间的钥匙也不用进去了

3、重复第二步,直到queue里所有的房间都去过,即queue为空
若room中有不为False的,就说明没进去过,返回False,否则返回True

例如:[[1,3],[3,0,1],[2],[0]]
初始化queue=[1,3], rooms = [False,[3,0,1],[2],[0]]

1出queue,[3,0,1]进queue, queue=[3,3,0,1], rooms = [False,False,[2],[0]]
3出queue,[0]进queue, queue=[3,0,1,0], rooms = [False,False,[2],False]
3出queue,queue=[0,1,0], rooms = [False,False,[2],False]
0出queue,queue=[1,0], rooms = [False,False,[2],False]
1出queue,queue=[0], rooms = [False,False,[2],False]
0出queue,queue=[], rooms = [False,False,[2],False]
此时queue为空,rooms不全为False,返回False

class Solution(object):
    def canVisitAllRooms(self, rooms):
        """
        :type rooms: List[List[int]]
        :rtype: bool
        """
        queue, rooms[0] = rooms[0], False
        while queue:
            k = queue.pop(0)
            if rooms[k]:
                queue.extend(rooms[k])
                rooms[k] = False       
        return not any(rooms)
发布了64 篇原创文章 · 获赞 9 · 访问量 4351

猜你喜欢

转载自blog.csdn.net/Avery123123/article/details/103155435