leetcode-广度优先遍历/图

542. 01 矩阵

多源bfs

超时的解法

class Solution(object):
    def updateMatrix(self, mat):
        """
        :type mat: List[List[int]]
        :rtype: List[List[int]]
        """
        def bfs(x,y):
            heap = []
            directions = [(-1,0),(1,0),(0,-1),(0,1)]
            heapq.heappush(heap,(mat[x][y],(x,y)))
            visited = set()
            while heap:
                d,(x,y) = heapq.heappop(heap)
                if mat[x][y] == 0:
                    return d
                if (x,y) in visited:
                    continue
                visited.add((x,y))
                for direction in directions:
                    new_x = x + direction[0]
                    new_y = y + direction[1]
                    if 0 <= new_x < m and 0 <= new_y < n and (new_x,new_y) not in visited:
                        heapq.heappush(heap,(d+mat[new_x][new_y],(new_x,new_y)))
            return -1
        
        m = len(mat)
        n = len(mat[0])
        res = [[0 for _ in range(n)] for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if mat[i][j] == 1:
                    d = bfs(i,j)
                    res[i][j] = d
        return res

279 完全平方数

思路就是bfs,自己解法1的bfs超时,看官方答案解法2的bfs的,用Set来代替加入list再去重。

解法1


class Solution:
    def numSquares(self, n: int) -> int:
        if n == 1:
            return 1
        def sqr(n):
            i =1 
            sqr_i = i**2
            while i**2 <= n:
                yield i**2
                i+=1
        squre_list = list(sqr(n))

        mark_list =set()
        queue = []
        queue.append(n)
        level = 0
        while queue!= 0:
            level+=1
            size = len(queue)
            while size != 0:
                num = queue.pop(0)
                for i in squre_list:
                    next_num = num -i
                    if next_num == 0:
                        return level
                    if next_num  < 0:
                        break
                    if next_num  not in mark_list:
                        mark_list.add(next_num )
                        queue.append(next_num )
                size -= 1
def helper(n):
    i=1
    alist=[]
    while i**2<n:
        alist.append(i**2)
        i=i+1
    return alist


def build_model_v2(n):
    alist=helper(n)
    mask_list=[]
    print(alist)
    queen.append(n)
    level=0
    #队列先进先出
    #在最开始把当前level的size保存下来,然后循环pop直到当前的size为0,就可以保证队列里每次都是cur_level的值
    while len(queen)>0:
        size=len(queen)
        level=level+1
        while size>=0:
            num=queen.pop(0)
            for i in range(len(alist)):
                next_num=num-alist[i]
                #下一层
                if next_num=0:
                    return level
                if next_num<0:
                    break
                if next_num>0 and next_num not in mask_list:
                    queen.append(next_num)
                    mask_list.append(next_num)
            size=size-1
                    

解法2

Leetcode-279. 完全平方数,BFS建模深度分析 - 简书

和二叉树层次遍历一样

class Solution:
    def numSquares(self, n):

        # list of square numbers that are less than `n`
        square_nums = [i * i for i in range(1, int(n**0.5)+1)]
    
        level = 0
        queue = {n}
        while queue:
            level += 1
            #! Important: use set() instead of list() to eliminate the redundancy,
            # which would even provide a 5-times speedup, 200ms vs. 1000ms.
            next_queue = set()
            # construct the queue for the next level
            for remainder in queue:
                for square_num in square_nums:    
                    if remainder == square_num:
                        return level  # find the node!
                    elif remainder < square_num:
                        break
                    else:
                        next_queue.add(remainder - square_num)
            queue = next_queue
        return level

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        square=[]
        for i in range(1,n+1):
            if i*i<=n:
                square.append(i*i)
        print(square)
        #广度优先遍历,当本层出现n为0的时候,返回
        from collections import deque
        deque=deque()
        deque.append((n,0))
        visited_val=set()
        visited_val.add(n)
        while deque:
            cur,d=deque.popleft()
            if cur==0:
                return d
            next_node=[]
            for val in square:
                if val<=cur and cur-val not in visited_val:
                    deque.append((cur-val,d+1))
                    visited_val.add(cur-val)

127 单词接龙

bfs找最短路径

力扣https://leetcode-cn.com/problems/word-ladder/solution/yan-du-you-xian-bian-li-shuang-xiang-yan-du-you-2/

class Solution(object):
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        from collections import deque
        deq = deque()
        deq.append((beginWord,1))
        visited = set() #防止往回搜
        visited.add(beginWord)
        wordList_set = set(wordList) #转化为set查询快
        chars=[]
        #生成26个字母
        for i in range(97,123):
            chars.append(chr(i))
        while deq:
            cur,d = deq.popleft()
            if cur == endWord:
                return d 
            for i in range(len(cur)):
                for j in range(len(chars)):
                    nexts = cur[:i] + chars[j] + cur[i+1:]  #当前单词的下一层
                    if nexts in wordList_set and nexts not in visited:
                        visited.add(nexts)
                        deq.append((nexts,d+1))
        return 0

注意:

在查找wordlist的时候,要把wordlist转化为set,不然会超时。

python在列表和集合中查找数据的区别(时间复杂度)_菜菜的博客-CSDN博客

单词接龙2

bfs找最短路+回溯

力扣

力扣

bfs得到word_next,word_level,dfs的循环条件

bfs+dfs

import string
import collections
class Solution(object):
    def findLadders(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: List[List[str]]
        """
        # 思路:bfs建图,找到当前word的level;dfs深搜找到每个序列。
        # bfs建图和127一样,额外需要把当前word的level保存下来。
        lowercase = list(string.ascii_lowercase)  # 26个小写字母列表
        visited = [beginWord]
        queen = [beginWord]
        # key: word, value: a list of next words
        word_next = collections.defaultdict(list)
        # key: word, value: level
        word_level = collections.defaultdict(int)
        word_level[beginWord]=1
        step = 1
        while queen:
            cur_size = len(queen)
            for h in range(cur_size):
                cur_word = queen.pop(0)
                # 对cur word的每个字母遍历,找到符合条件的。
                cur_word_list = list(cur_word)
                for i in range(len(cur_word_list)):
                    cur_i = cur_word_list[i]
                    # 用26个字母替换
                    for j in lowercase:
                        if j != cur_i:
                            next_word = ''.join(cur_word_list[:i]) + j + ''.join(cur_word_list[i + 1:])
                            if next_word in wordList:
                                if next_word not in visited:
                                    queen.append(next_word)
                                    visited.append(next_word)
                                    word_level[next_word]=step+1
                                    if next_word==endWord:
                                        word_next[cur_word].append(next_word)
                                        break
                                word_next[cur_word].append(next_word)
            step = step + 1

        # dfs深搜求解;终止条件是cur word=end word;循环机制是对下层单词循环
        def backtrack(word, path):
            if word == endWord:
                if path not in res:
                    res.append(path[:])
                return
            for w in word_next[word]:
                # 这个单词在当前单词的下一层
                if word_level[w] == word_level[word] + 1:
                    path.append(w)
                    backtrack(w, path)
                    path.pop()

        res = []
        backtrack(beginWord, [beginWord])
        return res
class Solution:
    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        from collections import deque
        from collections import defaultdict
        deq = deque()
        deq.append((beginWord,1))
        visited = set()
        visited.add(beginWord)
        wordList_set = set(wordList)
        maps = defaultdict(list) #存储每个单词的下一层单词
        maps_level = defaultdict(int) #存储这个单词位于哪层
        chars=[]
        for i in range(97,123):
            chars.append(chr(i))
        while deq:
            cur,d = deq.popleft()
            maps_level[cur] = d
            if cur == endWord:
            #     # max_level = d  #总共的层数
               break  #bfs终止
            for i in range(len(cur)):
                for j in range(len(chars)):
                    nexts = cur[:i] + chars[j] + cur[i+1:] #当前单词的下一层单词
                    if nexts in wordList_set:
                        if nexts not in  maps[cur]:
                            maps[cur].append(nexts) #存储每个单词的下一层单词.要加在visit之前,不然被前一层的下一个相同节点只能存上一个
                        if nexts not in visited:
                            visited.add(nexts)
                            deq.append((nexts,d+1))
        # print(maps)
        #用回溯搜索路径,level表示层数
        res=[]
        path=[]
        def dfs(cur_word,level):
            if cur_word == endWord:
                if path not in res:
                    res.append(path[:])
                    return 
            for i in range(len(maps[cur_word])):
                tmp = maps[cur_word][i]
                if maps_level[tmp] == level + 1:
                    path.append(tmp)
                    dfs(tmp,level+1)
                    path.pop()
        path.append(beginWord)
        dfs(beginWord,1)
        return res

走迷宫

 

def hasPath(maze, start, destination):
    m,n=len(maze),len(maze[0])
    direcs=[(1,0),(0,-1), (0,1),(-1,0)]
    start,destination=tuple(start),tuple(destination)
    # 下面广度优先遍历
    que=[start]
    visited=set([start])
    while que:
        pos=que.pop(0)
        for direc in direcs:
            nex_pos=roll(pos, direc, maze)
            if nex_pos==destination: return True
            if nex_pos not in visited:
                que.append(nex_pos)
                visited.add(nex_pos)
    return False

# 返回从pos=(x,y) 沿着direc=(dx, dy)方向 能到达的位置
def roll(pos, direc, maze):
    m, n=len(maze),len(maze[0])
    x, y=pos
    dx, dy=direc
    steps=0
    # 只要不出界and不碰到墙 就严格一个方向滚
    while 0<=x<m and 0<=y<n and maze[x][y]==0:
        # print('maze[{}][{}]={}'.format(x,y,maze[x][y]))
        x,y=x+dx, y+dy
    # 因为出界/撞墙导致循环停止 因此后退一步
    x, y=x-dx, y-dy
    return (x,y)   

作者:yuer-flyfly
链接:https://leetcode-cn.com/problems/the-maze/solution/mi-gong-tu-pu-tong-bfs-python-by-yuer-fl-0e6x/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
from collections import deque
class Solution(object):
    def hasPath(self, maze, start, destination):
        """
        :type maze: List[List[int]]
        :type start: List[int]
        :type destination: List[int]
        :rtype: bool
        """
        queue=deque()
        queue.append((start[0],start[1]))
        dires=[(-1,0),(1,0),(0,-1),(0,1)]
        visited=[[False for _ in range(len(maze[0]))] for _ in range(len(maze))]
        visited[start[0]][start[1]]=True
        while queue:
            x,y=queue.popleft()
            #往四个方向走,直到撞到墙壁为止
            for dire in dires:
                r,c = x,y
                #只要不出界and不碰到墙 就严格一个方向滚
                while 0<=r<len(maze) and 0<=c<len(maze[0]) and maze[r][c]==0:
                    r=r+dire[0]
                    c=c+dire[1]
                #退回一个是正常位置
                r=r-dire[0]
                c=c-dire[1]
                if visited[r][c]==False:
                    queue.append((r,c))
                    visited[r][c]=True
                if [r,c]==destination:
                    return True
        return False

岛屿数量

深度优先搜索

class Solution(object):
    def dfs(self,grid,i,j):
        #不符合条件就返回
        if not 0 <= i < len(grid) or not 0 <= j < len(grid[0]) or grid[i][j] == '0':
             return
        #遍历过这里就标记伟0
        grid[i][j] = '0'
        self.dfs(grid, i + 1, j)
        self.dfs(grid, i, j + 1)
        self.dfs(grid, i - 1, j)
        self.dfs(grid, i, j - 1)

    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        #dfs
        count=0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == '1':
                    self.dfs(grid,i,j)
                    count=count+1
        return count

广度优先搜索

同样地,我们也可以使用广度优先搜索代替深度优先搜索。

为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1
则将其加入队列,开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的 
1都会被重新标记为0。直到队列为空,搜索结束。

最终岛屿的数量就是我们进行广度优先搜索的次数。

LeetCode200. 岛屿数量(python,bfs)_rosefun96的博客-CSDN博客

from collections import deque
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        #bfs
        if len(grid) == 0:
            return 0
        queue = deque()
        num_island = 0
        dx = [1,0,-1,0]
        dy = [0,1,0,-1]
        visited = set()
        queue2 = deque()

        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == "1":
                    x,y = i,j
                    if (x, y) in visited:
                        continue
                    else:
                        visited.add((x,y))
                        num_island += 1
                    queue2.append((x,y))
                    while len(queue2) > 0:
                        x,y = queue2.popleft()
                        for k in range(4):
                            new_x = x+dx[k]
                            new_y = y+dy[k]
                            if new_x>=len(grid) or new_y>=len(grid[0]) or new_x<0 or new_y<0:
                                continue
                            if (new_x, new_y) not in visited:
                                visited.add((new_x,new_y))
                                if grid[new_x][new_y] == "1":
                                    queue2.append((new_x,new_y))
        return num_island
from collections import deque
class Solution(object):
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        res=0
        queue=deque()
        dires=[(-1,0),(1,0),(0,-1),(0,1)]
        visited=[[False for _ in range(len(grid[0]))] for _ in range(len(grid))]
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]=='1' and visited[i][j]==False:
                    res+=1
                    queue.append((i,j))
                    while queue:
                        x,y = queue.popleft()
                        #四个方向
                        for dire in dires:
                            r=x+dire[0]
                            c=y+dire[1]
                            if 0<=r<len(grid) and 0<=c<len(grid[0]) and grid[r][c]=='1' and visited[r][c]==False:
                                queue.append((r,c))
                                visited[r][c]=True
        return res

并查集

力扣

岛屿数量2

 并查集

class union_find(object):
    def __init__(self, n):
        self.root=[i for i in range(n)]
        self.rank=[i for i in range(n)]
        self.part=0
 
    def find(self, x):
        if x != self.root[x]:
            self.root[x] = self.find(self.root[x])
        return self.root[x]
 
    def union(self, x,y):
        rootX = self.find(x)
        rootY = self.find(y)
        if rootX!=rootY:
            if self.rank[rootX] > self.rank[rootY]:
                self.root[rootY] = rootX
            elif self.rank[rootX] < self.rank[rootY]:
                self.root[rootX] = rootY
            else:
                self.root[rootY] = rootX
                self.rank[rootX] += 1
            self.part=self.part-1

class Solution(object):
    def numIslands2(self, m, n, positions):
        """
        :type m: int
        :type n: int
        :type positions: List[List[int]]
        :rtype: List[int]
        """
        Row, Col = m, n
        uf=union_find(m*n)
        res = []
        seen = set()        #在并查中的,已经是陆地的位置
        for r,c in positions:
            ID = r * Col + c
            if ID in seen:                              #样例中有重复
                res.append(uf.part)
                continue
            seen.add(ID)
            uf.part += 1    #先加上,再考虑合并
            for nr, nc in ((r-1,c), (r+1,c), (r,c-1), (r,c+1)):
                if 0 <= nr < Row and 0 <= nc < Col:     #在版图内
                    id2 = nr * Col + nc
                    if id2 in seen:                     #已经是陆地了
                        uf.union(ID, id2)
            res.append(uf.part)
        return res

130 被围绕的区域

开始的做法:就像岛屿数量一样。但是这样有case判断不了,如下:

class Solution(object):
    def solve(self, board):
        """
        :type board: List[List[str]]
        :rtype: None Do not return anything, modify board in-place instead.
        """
        def dfs(i,j):
            #返回条件
            if not 0<=i<len(board)or not 0<j=<len(board[0]) or board[i][j]!="O":
                return 
            #遍历过标记为m
            board[i][j]="M"
            dfs(i+1,j)
            dfs(i-1,j)
            dfs(i,j+1)
            dfs(i,j-1)
        
        for i in range(1,len(board)-1):
            for j in range(1,len(board[0])-1):
                if board[i][j]=='O':
                    dfs(i,j)
        return board

正确的做法:

反向思维。从边界开始遍历,与边界的0联通的x,说明不能进行转化。其他的都是不与边界联通的,可以转化。

class Solution(object):
    def solve(self, board):
        """
        :type board: List[List[str]]
        :rtype: None Do not return anything, modify board in-place instead.
        """
        def dfs(i,j):
            if not 0<=i<len(board) or not 0<=j<len(board[0]) or board[i][j]!="O":
                return 
            board[i][j]='M'
            dfs(i+1,j)
            dfs(i-1,j)
            dfs(i,j+1)
            dfs(i,j-1)
        m=len(board)
        n=len(board[0])
        #遍历左右边界
        for i in range(m):
            dfs(i,0)
            dfs(i,n-1)
        #遍历上下边界
        for j in range(n):
            dfs(0,j)
            dfs(m-1,j)
        #遍历数组
        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j]=="O":
                    board[i][j]='X'
                elif board[i][j]=="M":
                    board[i][j]='O'

286 墙与门

dfs超时

class Solution(object):
    def wallsAndGates(self, rooms):
        """
        :type rooms: List[List[int]]
        :rtype: None Do not return anything, modify rooms in-place instead.
        """
        def dfs(i,j,val):
            #返回条件
            #rooms[i][j]<val 说明,以前的值比较小的话,就不遍历了。
            if not 0<=i<len(rooms) or not 0<=j<len(rooms[0]) or rooms[i][j]<val:
                return 
            rooms[i][j]=val
            dfs(i,j+1,val+1)
            dfs(i,j-1,val+1)
            dfs(i+1,j,val+1)
            dfs(i-1,j,val+1)

        for i in range(len(rooms)):
            for j in range(len(rooms[0])):
                if rooms[i][j]==0:
                    dfs(i,j,0)
        return rooms

多源bfs

import collections
class Solution(object):
    def wallsAndGates(self, rooms):
        """
        :type rooms: List[List[int]]
        :rtype: None Do not return anything, modify rooms in-place instead.
        """
        queue = collections.deque()
        for x in range(len(rooms)):
            for y in range(len(rooms[0])):
                if rooms[x][y] == 0:
                    queue.append(((x, y), 0))  ## 先加入队列,最后统一搜索
        while queue:
            (x, y), dis = queue.popleft()
            for nx, ny in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
                if 0 <= nx <= len(rooms)-1 and 0 <= ny <= len(rooms[0])-1:
                    if rooms[nx][ny] != 0 and rooms[nx][ny] != -1 and rooms[nx][ny] == 2147483647:
                        # 不越界且不是墙且没更新过
                        queue.append(((nx, ny), dis+1))
                        rooms[nx][ny] = dis + 1
        return rooms

5973. 价格范围内最高排名的 K 样物品

分层bfs

 

我的做法:bfs板子题

class Solution(object):
    def highestRankedKItems(self, grid, pricing, start, k):
        """
        :type grid: List[List[int]]
        :type pricing: List[int]
        :type start: List[int]
        :type k: int
        :rtype: List[List[int]]
        """
        # 广度优先搜索。
        # 往上下左右四个方向走,如果遇到为1的格子,不能过去,其他可以过去。
        # 求出来到符合价格的格子的最小步
        import collections
        queue = collections.deque()
        queue.append(((start[0], start[1]), 0))
        visited = []
        visited.append((start[0], start[1]))
        res = []
        res2 = []
        res3= []
        #判断起点元素是否符合要求
        nx=start[0]
        ny=start[1]
        if grid[nx][ny] >= pricing[0] and grid[nx][ny] <= pricing[1]:
            res.append(((nx, ny), 0))
            res2.append([nx, ny])
            res3.append(0)
        while queue:
            (x, y), distance = queue.popleft()
            for nx, ny in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]:
                if 0 <= nx <= len(grid) - 1 and 0 <= ny <= len(grid[0]) - 1 and (nx, ny) not in visited:
                    if grid[nx][ny] != 0:
                        queue.append(((nx, ny), distance + 1))
                        visited.append((nx, ny))
                        print(queue)
                        # 判断是否在要找的价格范围内
                        if grid[nx][ny] >= pricing[0] and grid[nx][ny] <= pricing[1]:
                            #当距离相同时,判断其他三个条件
                            if res3 and distance+1 == res3[-1]:
                                #如果当前价格小,插到前面.不能保证比所有这个距离的都小。
                                if grid[nx][ny]<grid[res2[-1][0]][res2[-1][1]]:
                                    insert_index=len(res)-1
                                    res.insert(insert_index,((nx, ny), distance + 1))
                                    res2.insert(insert_index,[nx, ny])
                                    res3.insert(insert_index,distance + 1)
                                    #价格相等的时候,行坐标:较小 行坐标的有更高优先级。
                                elif grid[nx][ny]==grid[res2[-1][0]][res2[-1][1]] and nx<res2[-1][0]:
                                    insert_index = len(res) - 1
                                    res.insert(insert_index, ((nx, ny), distance + 1))
                                    res2.insert(insert_index, [nx, ny])
                                    res3.insert(insert_index, distance + 1)
                                elif grid[nx][ny]==grid[res2[-1][0]][res2[-1][1]] and nx==res2[-1][0] and ny<res2[-1][1]:
                                    insert_index = len(res) - 1
                                    res.insert(insert_index, ((nx, ny), distance + 1))
                                    res2.insert(insert_index, [nx, ny])
                                    res3.insert(insert_index, distance + 1)
                                else:
                                    res.append(((nx, ny), distance + 1))
                                    res2.append([nx, ny])
                                    res3.append(distance + 1)
                            else:
                                res.append(((nx, ny), distance + 1))
                                res2.append([nx, ny])
                                res3.append(distance+1)
        print(res)
        if len(res2) > k:
            return res2[:k]
        return res2
class Solution:
    def highestRankedKItems(self, grid: List[List[int]], pricing: List[int], start: List[int], k: int) -> List[List[int]]:
        # BFS
        M = len(grid)
        N = len(grid[0])
        res = []

        q = collections.deque([tuple(start)])
        visited = set([tuple(start)])
        while q and len(res) < k:
            tmp = []
            for _ in range(len(q)):
                x, y = q.popleft()
                if pricing[0] <= grid[x][y] <= pricing[1]:
                    tmp.append((x, y))
                for nx, ny in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
                    if 0 <= nx < M and 0 <= ny < N and grid[nx][ny] != 0 and (nx, ny) not in visited:
                        q.append((nx, ny))
                        visited.add((nx, ny))
            tmp.sort(key = lambda x: (grid[x[0]][x[1]], x[0], x[1]))
            res += tmp
        return res[:k]

作者:linzeyin
链接:https://leetcode-cn.com/problems/k-highest-ranked-items-within-a-price-range/solution/jian-dan-yi-dong-ji-mo-ban-hua-de-bfsxie-ssbo/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

此题细节较多:

1.如果起点满足价格条件,得把起点也加入到res中去排序

2.无论当前点的价格符合不符合要求,都要

deq.append(((new_x, new_y), d + 1))

3.最后返回的时候,要判断一下res和k的关系

class Solution:
    def highestRankedKItems(self, grid: List[List[int]], pricing: List[int], start: List[int], k: int) -> List[List[int]]:
        # 求最短路径,并按照价格和坐标排序
        from collections import deque
        deq = deque()
        deq.append(((start[0], start[1]), 0))
        directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        visited = set()
        visited.add((start[0], start[1]))
        res = []
        if grid[start[0]][start[1]]>= pricing[0] and grid[start[0]][start[1]]<= pricing[1]:
            res.append([0, grid[start[0]][start[1]], start[0], start[1]])
        while deq:
            (cur_x, cur_y), d = deq.popleft()
            for direction in directions:
                new_x = cur_x + direction[0]
                new_y = cur_y + direction[1]
                if new_x >= 0 and new_x < len(grid) and new_y >= 0 and new_y < len(grid[0]) and (
                new_x, new_y) not in visited and grid[new_x][new_y]!=0:
                    if grid[new_x][new_y] >= pricing[0] and grid[new_x][new_y] <= pricing[1]:
                        res.append([d+1,grid[new_x][new_y], new_x, new_y])
                    deq.append(((new_x, new_y), d + 1))
                    visited.add((new_x, new_y))
        res.sort(key=lambda k: (k[0], k[1], k[2]), reverse=False)
        res2=[]
        if len(res)>=k:
            for i in range(k):
                res2.append([res[i][2],res[i][3]])
        else:
             for i in range(len(res)):
                res2.append([res[i][2],res[i][3]])
        return res2

2045. 到达目的地的第二短时间

 

 

这个题的难点不在于bfs,而在于如何求次短路径。与平时常见的bfs的区别是,没有visited。

另外一个是如何计算红绿灯时间。通过除法和余数的形式

建图+次短路

class Solution:
    def secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
        #bfs加入队列,求路径
        #先把图转化成邻接矩阵
        graph = [[] for _ in range(n + 1)]
        for e in edges:
            x, y = e[0], e[1]
            graph[x].append(y)
            graph[y].append(x)
        from collections import deque
        deque=deque()
        #起点
        deque.append(edges[0][0])
        while deque:
            #记录层数。因为要计算什么时候出红灯
            tmp=[]
            for i in range(len(deque)):
                cur_node=deque.popleft()
                #与他相临的的节点
                next_nodes=graph[cur_node]
                for next_node in next_nodes:
                    deque.append(next_node)
class Solution:
    def secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
        #bfs加入队列,求路径
        #先把图转化成邻接矩阵
        graph = [[] for _ in range(n + 1)]
        for e in edges:
            x, y = e[0], e[1]
            graph[x].append(y)
            graph[y].append(x)
        #存储起点到其他节点的最短路径和次短路径
        dist=[[-1]*2 for _ in range(n+1)]
        from collections import deque
        deque=deque()
        #起点。图中有 n 个节点,从 1 到 n 编号
        #deque记录起点到其他点的距离
        deque.append((1,0))
        while deque:
            cur_node,d = deque.popleft()
            #最短路径
            if dist[cur_node][0]==-1:
                dist[cur_node][0]=d
            #次短路径
            elif dist[cur_node][1]==-1 and dist[cur_node][0]<d:
            # elif dist[cur_node][1]==-1:
                dist[cur_node][1]=d
            else:
                continue
            next_nodes=graph[cur_node]
            for next_node in next_nodes:
                deque.append((next_node,d+1))
        second_dist=dist[-1][1]
        res=0
        # 计算通过红绿灯的时间
        for i in range(second_dist):
            #如果红绿灯切换次数为奇数,则现在是红灯
            if res//change % 2 ==1:
                #等到绿灯再出发(红灯剩余时间)
                res+=change-res%change
            res+=time
        return res
        # 计算通过红绿灯的时间
        # for i in range(second_dist):            
        #     if (res//change)&1:
        #         res=res//change*change+change
        #     res+=time
        # return res

2039. 网络空闲的时刻

 

 建图+最短路

class Solution:
    def networkBecomesIdle(self, edges: List[List[int]], patience: List[int]) -> int:
        from collections import deque
        deq=deque()
        #先找数据服务器到主服务器的路径,得到数据服务器发出消息到主服务器的时间
        #从路径最小的开始,计算它发出数据到变空闲的时间,取最大值
        #如何求每个节点到原点的最小路径呢?队列的方法
        #建图,然后求最短路
        n=len(patience)
        distance=[-1 for _ in range(n)]
        graph=[[] for _ in range(n)]
        for i in range(len(edges)):
            graph[edges[i][0]].append(edges[i][1])
            graph[edges[i][1]].append(edges[i][0])
        #节点0,到节点0的距离是0
        deq.append((0,0))
        while deq:
            cur_node,d=deq.popleft()
            next_nodes=graph[cur_node]
            for next_node in next_nodes:
                if distance[next_node]==-1:
                    distance[next_node]=d+1
                    deq.append((next_node,d+1))
        res=0
        #求每个节点,变为空闲的时间.
        #注意:在第一个收到0节点的回复之后,就不会再发送消息了
        for i in range(1,n):
            first_receive_time=distance[i]*2
            #在first_receive_time之前多发送了多少条
            m=(first_receive_time-1)//patience[i]
            #最后一条距离0时间多久
            other_time=patience[i]*m
            res=max(res,first_receive_time+other_time+1)
        return res

1765. 地图中的最高点

 

我的解法:超时了。看了答案之后,是先把水域全都加到队列,然后在搜。

class Solution(object):
    def highestPeak(self, isWater):
        """
        :type isWater: List[List[int]]
        :rtype: List[List[int]]
        """
        #  [[0,0,1],
        #  [1,1,0],
        #  [0,1,0]]
        #思路:新建一个高度矩阵,从水域开始,值为1的,设置为0
        #然后遍历上下左右四个方向。每次加1。
        #当遍历到一个新的水域时,如果他的上下左右方向有值,取最小值。比如如果以前时2,但是这个新水域算的是1,就取1。
        m=len(isWater)
        n=len(isWater[0])
        from collections import deque
        deque=deque()
        height=[[-1 for _ in range(n)] for _ in range(m)]
        directs=[(-1,0),(1,0),(0,-1),(0,1)]
        for i in range(m):
            for j in range(n):
                if isWater[i][j]==1:
                    deque.append([(i,j),0])
                    visited=[[False for _ in range(n)] for _ in range(m)]
                    visited[i][j]=True
                    while deque:
                        (x,y),d=deque.popleft()
                        if height[x][y]!=-1 and height[x][y]>d:
                            height[x][y]=d
                        if height[x][y]==-1:
                            height[x][y]=d
                        #上下左右四个方向
                        for (dx,dy) in directs:
                            if x+dx>=0 and x+dx<m and y+dy>=0 and y+dy<n and visited[x+dx][y+dy]==False and isWater[x+dx][y+dy]!=1:
                                deque.append([(x+dx,y+dy),d+1])
                                visited[x+dx][y+dy]=True
        return height
class Solution(object):
    def highestPeak(self, isWater):
        """
        :type isWater: List[List[int]]
        :rtype: List[List[int]]
        """
        #  [[0,0,1],
        #  [1,1,0],
        #  [0,1,0]]
        #思路:新建一个高度矩阵,从水域开始,值为1的,设置为0
        #然后遍历上下左右四个方向。每次加1。
        #当遍历到一个新的水域时,如果他的上下左右方向有值,取最小值。比如如果以前时2,但是这个新水域算的是1,就取1。
        m=len(isWater)
        n=len(isWater[0])
        from collections import deque
        deque=deque()
        height=[[-1 for _ in range(n)] for _ in range(m)]
        directs=[(-1,0),(1,0),(0,-1),(0,1)]
        visited=[[False for _ in range(n)] for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if isWater[i][j]==1:
                    deque.append([(i,j),0])
                    visited[i][j]=True
        while deque:
            (x,y),d=deque.popleft()
            if height[x][y]!=-1 and height[x][y]>d:
                height[x][y]=d
            if height[x][y]==-1:
                height[x][y]=d
            #上下左右四个方向
            for (dx,dy) in directs:
                if x+dx>=0 and x+dx<m and y+dy>=0 and y+dy<n and visited[x+dx][y+dy]==False and isWater[x+dx][y+dy]!=1:
                    deque.append([(x+dx,y+dy),d+1])
                    visited[x+dx][y+dy]=True
        return height

剑指offer112 最长递增路径

图的遍历,深度优先

class Solution:
    # 图的遍历,深度优先遍历。
    # 从较小的数指向较大的数,有向无环图
    def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
        m, n = len(matrix), len(matrix[0])
        if m == 0 or n == 0:
            return 0
        lengths = [[0] * n for _ in range(m)]
        longest = 0
        for i in range(m):
            for j in range(n):
                length = self.dfs(matrix, lengths, i, j)
                longest = max(longest, length)
        return longest

    def dfs(self, matrix, lengths, i, j):
        if lengths[i][j] != 0:  # 如果值不为0,说明之前已经计算过以坐标(i, j)为起点的最长递增路径的长度,矩阵lengths起到缓存的作用,确保以任意坐标为起点的最长递增路径的长度只需计算一次。
            return lengths[i][j]
        rows, cols = len(matrix), len(matrix[0])
        dirs = [(-1, 0), (0, -1), (1, 0), (0, 1)]
        length = 1
        for dir in dirs:
            r = i + dir[0]
            c = j + dir[1]
            if r >= 0 and r < rows and c >= 0 and c < cols and matrix[r][c] > matrix[i][j]:
                path = self.dfs(matrix, lengths, r, c)
                length = max(path + 1, length)
        lengths[i][j] = length
        return length

作者:you-lan-10
链接:https://leetcode-cn.com/problems/fpTFWP/solution/jian-zhi-offer112-zui-chang-di-zeng-lu-j-j775/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution(object):
    def longestIncreasingPath(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: int
        """
        def dfs(i,j):
            if lengths[i][j]>0:
                return lengths[i][j]
            length=1
            #上下左右移动
            dirs=[(-1,0),(1,0),(0,-1),(0,1)]
            for cur_dir in dirs:
                r=i+cur_dir[0]
                c=j+cur_dir[1]
                if 0<=r<len(matrix) and 0<=c<len(matrix[0]) and matrix[r][c]>matrix[i][j]:
                    path=dfs(r,c)
                    #保证取到的是循环中最大的那个path
                    length=max(path+1,length)
                    # length=path+1
            lengths[i][j]=length
            return length
        #遍历,找以每个元素为起点的最长递增路径
        res=1
        lengths=[[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                cur=dfs(i,j)
                res=max(cur,res)
        return res

        [[7,7,5],
        [2,4,6],
        [8,2,0]]

                

5544 执行操作后字典序最小的字符串

这是一个周赛题,当时没做出来,后来看题解,居然是dfs or bfs 遍历。。。

class Solution(object):
    def lunzhuan(self,s,b):
        alist=list(s)
        s1=alist[-b:]
        s2=alist[:len(s)-b]
        return ''.join(str(i) for i in s1+s2)
    def leijia(self,s,a):
        alist=list(s)
        for i in range(len(s)):
            if i%2 !=0:
                alist[i]=int(alist[i])+a
                if alist[i]>=9:
                    alist[i]=alist[i]%10
        return ''.join(str(i) for i in alist)
    def findLexSmallestString(self, s, a, b):
        ans = '9' * 100
        queue = [s]
        visited = set()
        visited.add(s)
        while queue:
            len_ = len(queue)
            while len_:
                p = queue.pop(0)
                ans = min(ans,p)
                m,e = self.leijia(p,a),self.lunzhuan(p,b)
                if m not in visited:
                    queue.append(m)
                    visited.add(m)
                if e not in visited:
                    queue.append(e)
                    visited.add(e)
                len_ -= 1
        return ans

5548. 最小体力消耗路径

回溯

class Solution(object):
    def __init__(self):
        self.res = []
        self.min_v = float("inf")
    def chazhi(self,num):
        max_v=0
        for i in range(len(num)-1):
            diff= abs(num[i+1]-num[i])
            if diff>max_v:
                max_v=diff
        return max_v
    def minimumEffortPath(self, heights):
        """
        :type heights: List[List[int]]
        :rtype: int
        """
        rows=len(heights)
        cols=len(heights[0])
        path=[]
        boolmatrix = [0] * (rows * cols)
        self.helper(heights, rows, cols, 0, 0, path,boolmatrix)
        return self.min_v
    def helper(self, matrix, rows, cols, row, col, path,boolmatrix):
        path.append(matrix[row][col])
        boolmatrix[row*cols + col] = True
        if row==rows-1 and col==cols-1:
            cur_v = self.chazhi(path)
            if cur_v<self.min_v:
                self.min_v=cur_v
                if self.min_v == 0:
                    return 
            return 
        if row+1<rows and col<cols and not boolmatrix[(row+1)*cols + col]:
            self.helper(matrix, rows, cols, row+1, col, path,boolmatrix)
            boolmatrix[(row+1)*cols + col] = False
            path.pop()
        if row-1>=0 and col<cols and not boolmatrix[(row-1)*cols + col]:
            self.helper(matrix, rows, cols, row-1, col, path,boolmatrix)
            path.pop()
            boolmatrix[(row-1)*cols + col] = False
        if row<rows and col+1<cols and not boolmatrix[row*cols + col+1]:
            self.helper(matrix, rows, cols, row, col+1, path,boolmatrix)
            path.pop()
            boolmatrix[row*cols + col+1]= False
        if row<rows and col-1>=0 and not boolmatrix[row*cols + col-1]:
            self.helper(matrix, rows, cols, row, col-1, path,boolmatrix)
            path.pop()
            boolmatrix[row*cols + col-1] = False

bfs

class Solution:
    def minimumEffortPath(self, heights: List[List[int]]) -> int:
        row=len(heights)
        col=len(heights[0])
        #distance 表示当前节点与 (0,0) 点最小体力消耗。
        distance=[[float('inf')]* col for _ in range(row)]
        distance[0][0]=0
        def bsf(queue):
            dd = [[0, 1], [1, 0], [0, -1], [-1, 0]]
            while queue:
                x, y,old_x,old_y = queue.pop(0)

                for i in dd:
                    new_x = x + i[0]
                    new_y = y + i[1]
                    #判断新访问节点合法的条件,在棋盘内,并且不能重复访问来时的节点
                    if 0 <= new_x < row and 0 <= new_y < col and (new_x,new_y)!=(old_x,old_y ):
                        if distance[new_x][new_y]>max(distance[x][y],abs(heights[new_x][new_y] - heights[x][y])):
                            #如果 (new_x,new_y) 点最小体力消耗改变,将此点加入广度搜索序列
                            distance[new_x][new_y]=max(distance[x][y],abs(heights[new_x][new_y] - heights[x][y]))
                            queue.append((new_x,new_y,x,y))
        bsf([(0,0,-1,-1)])
        return  distance[-1][-1]

作者:chang-qing-zi
链接:https://leetcode-cn.com/problems/path-with-minimum-effort/solution/python-yan-du-you-xian-sou-suo-by-chang-qing-zi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

并查集模版

算法:并查集 - 子烁爱学习 - 博客园

class Solution(object):
    def minimumEffortPath(self, heights):
        """
        :type heights: List[List[int]]
        :rtype: int
        """
        M = len(heights)
        N = len(heights[0])
        dsu = DSU()
        edges = []
        for i in range(M):
            for j in range(N):
                pos = i * N + j
                if i < M - 1:
                    #下边
                    edges.append([abs(heights[i + 1][j] - heights[i][j]), pos, pos + N])
                if j < N - 1:
                    #右边
                    edges.append([abs(heights[i][j + 1] - heights[i][j]), pos, pos + 1])
        edges.sort()
        for edge in edges:
            dsu.union(edge[1], edge[2])
            if dsu.connected(0, M * N - 1):
                return edge[0]
        return 0
        
class DSU:
    def __init__(self):
        self.par = range(10001)

    def find(self, x):
        if x != self.par[x]:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        self.par[self.find(x)] = self.find(y)
    
    def connected(self, x, y):
        return self.find(x) == self.find(y)

力扣

407 接雨水2

核心思想是:当确定一个外圈的最小值之后,以他为起点往四个方向遍历,如果遍历到的点小于他,那么肯定可以接满以他为高度的雨水。这里类似脑筋急转弯要想明白。

最小堆+广搜

(最小堆+广搜,其实就是迪杰斯特拉算法求最短路径问题)

class Solution:
    def trapRainWater(self, heightMap: List[List[int]]) -> int:
        if len(heightMap) <= 2 or len(heightMap[0]) <= 2:
            return 0

        m, n = len(heightMap), len(heightMap[0])
        visited = [[0 for _ in range(n)] for _ in range(m)]
        pq = []
        for i in range(m):
            for j in range(n):
                if i == 0 or i == m - 1 or j == 0 or j == n - 1:
                    visited[i][j] = 1
                    heapq.heappush(pq, (heightMap[i][j], (i, j)))

        res = 0
        dirs = [(-1, 0), (1, 0), (0, 1), (0, -1)]
        while pq:
            height, (position_x, position_y) = heapq.heappop(pq)
            for dir in dirs:
                nx, ny = position_x + dir[0], position_y + dir[1]
                if nx >= 0 and nx < m and ny >= 0 and ny < n and visited[nx][ny] == 0:
                    if height > heightMap[nx][ny]:
                        res += height - heightMap[nx][ny]
                    visited[nx][ny] = 1
                    heapq.heappush(pq, (max(height, heightMap[nx][ny]), (nx, ny)))
            # for k in range(4):
            #     nx, ny = position // n + dirs[k], position % n + dirs[k + 1]
            #     new_x,new_y = position_x + dirs[k]
            #     if nx >= 0 and nx < m and ny >= 0 and ny < n and visited[nx][ny] == 0:
            #         if height > heightMap[nx][ny]:
            #             res += height - heightMap[nx][ny]
            #         visited[nx][ny] = 1
            #         heapq.heappush(pq, (max(height, heightMap[nx][ny]), nx * n + ny))
        return res

 

class Solution:
    def trapRainWater(self, heightMap: List[List[int]]) -> int:
        m, n = len(heightMap), len(heightMap[0])
        maxHeight = max(max(row) for row in heightMap)
        water = [[maxHeight for _ in range(n)] for _ in range(m)]
        dirs = [-1, 0, 1, 0, -1]

        qu = []
        for i in range(m):
            for j in range(n):
                if i == 0 or i == m - 1 or j == 0 or j == n - 1:
                     if water[i][j] > heightMap[i][j]:
                        water[i][j] = heightMap[i][j]
                        qu.append([i, j])
        
        while len(qu) > 0:
            [x, y] = qu.pop(0)
            for i in range(4):
                nx, ny = x + dirs[i], y + dirs[i + 1]
                if nx < 0 or nx >= m or ny < 0 or ny >= n:
                    continue
                if water[x][y] < water[nx][ny] and water[nx][ny] > heightMap[nx][ny]:
                    water[nx][ny] = max(water[x][y], heightMap[nx][ny])
                    qu.append([nx, ny])

        ans = 0
        for i in range(m):
            for j in range(n):
                ans = ans + water[i][j] - heightMap[i][j]
        return ans

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/trapping-rain-water-ii/solution/jie-yu-shui-ii-by-leetcode-solution-vlj3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

class Solution {
public:
    priority_queue<pair<int, pair<int, int> >, vector<pair<int, pair<int, int> > >, greater<pair<int, pair<int, int> > > > pq;
    bool vis[201][201];
    int dirx[4] = {0, 0, 1, -1};
    int diry[4] = {1, -1, 0, 0};
    int trapRainWater(vector<vector<int>>& heightMap) {
        int n = heightMap.size(), m = heightMap[0].size(), ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (i == 0 || i == n - 1 || j == 0 || j == m - 1) {
                    pq.push(make_pair(heightMap[i][j], make_pair(i, j)));
                    vis[i][j] = true;
                }
            }
        }

        while (!pq.empty()) {
            int h = pq.top().first, x = pq.top().second.first, y = pq.top().second.second;
            pq.pop();
            for (int i = 0; i < 4; i++) {
                int nx = dirx[i] + x, ny = diry[i] + y;
                if (nx >= 0 && nx < n && ny >= 0 && ny < m && (!vis[nx][ny])) {
                    if (heightMap[nx][ny] < h) {
                        ans += h - heightMap[nx][ny];
                    }
                    vis[nx][ny] = 1;
                    pq.push(make_pair(max(heightMap[nx][ny], h), make_pair(nx, ny)));
                }
            }
        }
        return ans;
    }
};

作者:bianchengxiong
链接:https://leetcode-cn.com/problems/trapping-rain-water-ii/solution/acmjin-pai-ti-jie-zui-duan-lu-suan-fa-bi-zdax/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

743 网络延迟时间 Dijkstra

力扣

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        # 邻接矩阵
        g = [[float('inf')] * n for _ in range(n)]
        for x, y, time in times:
            g[x - 1][y - 1] = time

        # 距离数组
        dist = [float('inf')] * n
        dist[k - 1] = 0

        # 标记数组
        used = [False] * n
        for _ in range(n):
            # 找到未标记最近的点
            x = -1
            for y, u in enumerate(used):
                if not u and (x == -1 or dist[y] < dist[x]):
                    x = y
            
            # 更新
            used[x] = True
            for y, time in enumerate(g[x]):
                dist[y] = min(dist[y], dist[x] + time)

        ans = max(dist)
        return ans if ans < float('inf') else -1


作者:已注销
链接:https://leetcode-cn.com/problems/network-delay-time/solution/gtalgorithm-dan-yuan-zui-duan-lu-chi-tou-w3zc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

bfs

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        """广度优先搜索"""
        # 建图 - 邻接表
        mp = [{} for i in range(n + 1)]
        for u, v, t in times:
            mp[u][v] = t
        # 记录结点最早收到信号的时间
        res = [-1 for _ in range(n + 1)]
        res[k] = 0
        # 队列中存放 [结点,收到信号时间]
        import collections
        deque = collections.deque()
        deque.append((k,0))
        while deque:
            cur_node, t = deque.popleft()
            for next_node, need_time in mp[cur_node].items():
                art = t + need_time
                # 仅当结点未收到或收到时间比记录时间更早才更新并入队
                if res[next_node] == -1 or art < res[next_node]:
                    res[next_node] = art
                    deque.append([next_node, art])
        minT = -1
        for i in range(1, n + 1):
            if res[i] == -1:
                return -1
            minT = max(minT, res[i])
        return minT

dfs

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        """深度优先搜索"""
        # 建图 - 邻接表
        mp = [{} for i in range(n + 1)]
        for u, v, t in times:
            mp[u][v] = t
        # 记录结点最早收到信号的时间
        r = [-1 for i in range(n + 1)]

        def dfs(i: int, t: int) -> None:
            """在 t 时间到达 i 结点"""
            if r[i] == -1 or t < r[i]:
                r[i] = t
                for u, v in mp[i].items():
                    dfs(u, t + v)

        dfs(k, 0)

        minT = -1
        for i in range(1, n + 1):
            if r[i] == -1:
                return -1
            minT = max(minT, r[i])
        return minT

作者:meteordream
链接:https://leetcode-cn.com/problems/network-delay-time/solution/wang-luo-yan-chi-shi-jian-dan-yuan-zui-d-m1m3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2157. 字符串分组

class Solution(object):
    def groupStrings(self, words):
        """
        :type words: List[str]
        :rtype: List[int]
        """
        #判断两个单词的编辑距离
        def edite_distance(word1,word2):
            dp=[[0 for i in range(len(word2)+1)] for _ in range(len(word1)+1)]
            #初始化
            for i in range(len(word2)+1):
                dp[0][i]=i 
            for i in range(len(word1)+1):
                dp[i][0]=i
            #两层循环
            for i in range(1,len(word1)+1):
                for j in range(1,len(word2)+1):
                    if word1[i-1]==word2[j-1]:
                        dp[i][j]=dp[i-1][j-1]
                    else:
                        #word1删去一个元素
                        c1=dp[i-1][j]+1
                        #word2删去一个元素
                        c2=dp[i][j-1]+1
                        #改变一个元素
                        c3=dp[i-1][j-1]+1
                        dp[i][j]=min(c1,c2,c3)
            return dp[-1][-1]
        res1=[]
        #广度优先遍历即可
        visited=set()
        for i in range(len(words)):
            if words[i] not in visited:
                cur_node=[]
                cur_node.append(words[i])
                visited.add(words[i])
                cur_res=[]
                while cur_node:
                    cur_word2=cur_node.pop(0)
                    cur_res.append(cur_word2)
                    for j in range(len(words)):
                        if words[j] not in visited and cur_word2!=words[j]:
                            # 判断是否关联
                            if edite_distance(cur_word2,words[j])==1:
                                cur_node.append(words[j])
                                visited.add(words[j])
                res1.append(cur_res[:])
        print(res1)
        res=[]
        res.append(len(res1))
        a=0
        for i in range(len(res1)):
            a=max(a,len(res1[i]))
        res.append(a)
        return res

这么做能通过一些case,但是,题目要求是字符串集合是否相似,是不考虑前后顺序的。所以得用二进制。

1219 黄金矿工

 回溯

得用回溯,因为不回溯的话两圈之间会互相影响。

class Solution:
    def getMaximumGold(self, grid: List[List[int]]) -> int:
        #不能同时计算两个方向的,因此用dfs一搜到底
        directions=[(-1,0),(1,0),(0,-1),(0,1)]
        def dfs(i,j):
            a1,a2,a3,a4=0,0,0,0
            if i+1<len(grid) and grid[i+1][j]!=0 and (i+1,j) not in visited:
                visited.add((i+1,j))
                a1=dfs(i+1,j)+grid[i+1][j]
                visited.remove((i+1,j))
            if i-1>=0 and grid[i-1][j]!=0 and (i-1,j) not in visited:
                visited.add((i-1,j))
                a2=dfs(i-1,j)+grid[i-1][j]
                visited.remove((i-1,j))
            if j+1<len(grid[0]) and grid[i][j+1]!=0 and (i,j+1) not in visited:
                visited.add((i,j+1))
                a3=dfs(i,j+1)+grid[i][j+1]
                visited.remove((i,j+1))
            if j-1>=0 and grid[i][j-1]!=0 and (i,j-1) not in visited:
                visited.add((i,j-1))
                a4=dfs(i,j-1)+grid[i][j-1]
                visited.remove((i,j-1))
            return max(a1,a2,a3,a4)
        res=0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]!=0:
                    visited=set()
                    visited.add((i,j))
                    cur_ans=grid[i][j]+dfs(i,j)
                    print((i,j),cur_ans)
                    res=max(res,cur_ans)
        return res

回溯:用修改gird的方法,来防治往回走,代码简洁,类似于 单词搜索。

#从各个起点开始搜索,用grid[i][j]来标记走过的点,回溯。

# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
    def getMaximumGold(self, grid):
        # 往上下左右四个方向走
        def dfs(start_i,start_j):
            if start_i < 0 or start_i > len(grid)-1 or start_j < 0 or start_j > len(grid[0]) - 1 or grid[start_i][start_j] <= 0:
                return 0
            tmp =  grid[start_i][start_j]
            grid[start_i][start_j] = -1
            a1 = dfs(start_i+1,start_j) + tmp
            a2 = dfs(start_i - 1,start_j) + tmp
            a3 = dfs(start_i, start_j + 1)+ tmp
            a4 = dfs(start_i, start_j - 1)+ tmp
            grid[start_i][start_j] = tmp
            return max(a1,a2,a3,a4)

        res = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] > 0:
                    cur_res = dfs(i,j)
                    res = max(res,cur_res)
        return res

bfs:不太行

下面第一个是我写的bfs,通不过全部的case。

因为在bfs遍历的时候有一个visited数组,两圈之间可能会互相影响。

要是用bfs得用下面第二种那样,把visited加到队列里。

class Solution:
    def getMaximumGold(self, grid):
        # bfs板子题
        directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        res = 0
        from collections import deque
        deque = deque()
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] != 0:
                    cur_ans = 0
                    visited = set()
                    deque.append(((i, j), grid[i][j]))
                    visited.add((i, j))
                    while deque:
                        (x, y), value = deque.popleft()
                        cur_ans =max(cur_ans,value)
                        for derection in directions:
                            new_dx = x + derection[0]
                            new_dy = y + derection[1]
                            if new_dx >= 0 and new_dx < len(grid) and new_dy >= 0 and new_dy < len(grid[0]) and (
                            new_dx, new_dy) not in visited:
                                deque.append(((new_dx, new_dy), value+grid[new_dx][new_dy]))
                                visited.add((new_dx, new_dy))
                    print((i, j), cur_ans)
                    res = max(res, cur_ans)
        return res
    class Solution:
        def getMaximumGold3(self, grid) -> int:
            dirs = {(0, 1), (0, -1), (-1, 0), (1, 0)}
            m, n = len(grid), len(grid[0])
            ans = 0
            for i in range(m):
                for j in range(n):
                    if grid[i][j]:
                        q = deque([(i, j, grid[i][j], set([(i, j)]))])
                        while q:
                            x, y, v, vis = q.popleft()
                            ans = max(ans, v)
                            for dx, dy in dirs:
                                if 0 <= x + dx < m and 0 <= y + dy < n and grid[x + dx][y + dy] and (
                                x + dx, y + dy) not in vis:
                                    q.append((x + dx, y + dy, v + grid[x + dx][y + dy], vis | set([(x + dx, y + dy)])))
            return ans

2050. 并行课程 III

 

 

 分层bfs遍历

这么做只能通过一部分case.因为实际上并不是按照分层来的,比如上面那个例子,假如节点1的时间是10,那么节点1和其他节点的时间是并行的。

class Solution:
    def minimumTime(self, n: int, relations: List[List[int]], time: List[int]) -> int:
        #拓扑排序,记录每层的最大value
        #先建图
        graph=[[] for _ in range(n+1)]
        indegree=[0 for _ in range(n+1)]
        for pre,cur in relations:
            graph[pre].append(cur)
            indegree[cur]+=1
        print(indegree)
        print(graph)
        #找到入度为0的节点
        from collections import deque
        deq=deque()
        for i in range(1,len(indegree)):
            if indegree[i]==0:
                deq.append((i,time[i-1]))
        res=0
        while deq:
            cur_level_max_time=0
            loop_count=len(deq)
            print(loop_count)
            deque_next=deque()
            while loop_count>0:
                cur,cur_time =deq.popleft()
                cur_level_max_time=max(cur_level_max_time,cur_time)
                next_courses=graph[cur]
                print(next_courses)
                for next_course in next_courses:
                    indegree[next_course]-=1
                    if indegree[next_course]==0:
                        deque_next.append((next_course,time[next_course-1]))
                loop_count-=1
            deq=deque_next
            res+=cur_level_max_time
        return res

bfs+动态规划

用dp[next_course] = max(dp[next_course], dp[cur] + time[next_course - 1])

来更新,到当前节点所需要的最大时间。

class Solution:
    def minimumTime(self, n: int, relations: List[List[int]], time: List[int]) -> int:
        #拓扑排序,记录每层的最大value
        #先建图
        graph = [[] for _ in range(n + 1)]
        indegree = [0 for _ in range(n + 1)]
        dp = [0 for _ in range(n + 1)]
        for pre, cur in relations:
            graph[pre].append(cur)
            indegree[cur] += 1
        # 找到入度为0的节点
        from collections import deque
        deq = deque()
        for i in range(1, len(indegree)):
            dp[i] = time[i - 1]
            if indegree[i] == 0:
                deq.append(i)
        while deq:
            loop_count = len(deq)
            deque_next = deque()
            while loop_count > 0:
                cur = deq.popleft()
                #计算时间,前置任务的最大时间,加上当前节点的时间
                next_courses = graph[cur]
                for next_course in next_courses:
                    indegree[next_course] -= 1
                    dp[next_course] = max(dp[next_course], dp[cur] + time[next_course - 1])
                    if indegree[next_course] == 0:
                        deque_next.append(next_course)
                loop_count -= 1
            deq = deque_next
        return max(dp)

6063. 节点序列的最大得分

 枚举边,脑筋急转弯

dfs肯定超时

class Solution:
    def maximumScore(self, scores: List[int], edges: List[List[int]]) -> int:
        child = defaultdict(set)

        for a, b in edges:
            child[a].add(b)
            child[b].add(a)
        

        ans = -1

        edges.sort(key=lambda i:scores[i[0]] + scores[i[1]], reverse=True)

        for i in range(len(edges)):
            a, b = edges[i]
            for j in range(i + 1, len(edges)):
                c, d = edges[j]
                
                # 有重复点时跳过
                if a == c or a == d or b == c or b == d:
                    continue
                    
                tmp = scores[a] + scores[b] + scores[c] + scores[d]

                if tmp > ans:
                    # 两边连通
                    if a in child[c] or a in child[d] or b in child[c] or b in child[d]:
                        ans = max(ans, tmp)
                else: # 后面找不到更好的边了
                    break
        
        return ans


作者:you-zhu-yi-si-mou-mou-ren
链接:https://leetcode-cn.com/problems/maximum-score-of-a-node-sequence/solution/-by-you-zhu-yi-si-mou-mou-ren-1jtv/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

6134. 找到离给定两个节点最近的节点

 我的错误的做法,有的case不能通过

class Solution(object):
    def closestMeetingNode(self, edges, node1, node2):
        """
        :type edges: List[int]
        :type node1: int
        :type node2: int
        :rtype: int
        """
        import collections
        graph = collections.defaultdict(int)
        for i in range(len(edges)):
            graph[i] = edges[i]
        print(graph)
        if_circle = False
        path1 = [node1]
        next_node = graph[node1]
        while next_node not in path1 and next_node!= -1:
            if next_node == node2:
                if_circle = True
            path1.append(next_node)
            next_node = graph[next_node]
        path2 = [node2]
        next_node = graph[node2]
        while next_node not in path2 and next_node!= -1:
            if next_node == node1:
                if_circle = True
            path2.append(next_node)
            next_node = graph[next_node]
        print(path1,path2)
        print(if_circle)
        if not if_circle:
            a = [i for i in path1 if i in path2]
            print(a)
            if len(a) > 0:
                return a[0]
            return -1
        else:
            path2_back = path2[::-1]
            a1 = [i for i in path1 if i in path2_back]
            path1_back = path1[::-1]
            a2 = [i for i in path1_back if i in path2]
            print(a1,a2)
            #到a1的距离
            count1 = 0
            for i in range(len(path1)):
                if path1[i] == a1[0]:
                    break
                count1 += 1
            count2 = 0
            for i in range(len(path2)):
                if path2[i] == a2[0]:
                    break
                count2 += 1
            if count1 != count2:
                if count1 < count2:
                    return a1[0]
                return a2[0]
            else:
                if a1[0] < a2[0]:
                    return a1[0]
                return a2[0]
            # if a1[0] > a2[0]:
            #     return a2[0]
            # return a1[0]
# edges = [1,2,-1]
# node1 = 0
# node2 = 2
# # edges = [2,2,3,-1]
# node1 = 0
# node2 = 1
# edges = [5,-1,3,4,5,6,-1,-1,4,3]
# node1 = 0
# node2 = 0
# edges = [4,3,0,5,3,-1]
# node1 = 4
# node2 = 0
# 4
# edges = [4,4,4,5,1,2,2]
# node1 = 1
# node2 =1
# edges = [2,0,0]
# node1 = 2
# node2 = 0
#0
# edges = [5,3,1,0,2,4,5]
# node1 = 3
# node2 = 2
#3
# edges = [5,4,5,4,3,6,-1]
# node1 = 0
# node2 = 1
edges = [-1,7,15,15,-1,4,16,2,16,7,11,6,10,4,9,1,14,-1]
node1 = 1
node2 = 6
res = Solution().closestMeetingNode(edges, node1, node2)
print(res)

正确的解法

class Solution:
    def closestMeetingNode(self, edges: List[int], node1: int, node2: int) -> int:
        
        # BFS计算给定节点u到其后代节点的距离
        def bfs(u):
            visited = dict()
            step = 0
            while u != -1 and u not in visited:
                visited[u] = step
                u = edges[u]    # 节点u的子代节点
                step += 1
            return visited
        

        # 分别计算node1和node2到其后代节点的距离
        visited1 = bfs(node1)
        visited2 = bfs(node2)
        
        ans = (-1, 10**9)       # (节点编号,对应距离的较大值)
        for node in visited1:
            if node in visited2:
                dist = max(visited1[node], visited2[node])  # 更新结果
                if dist < ans[1] or (dist == ans[1] and node < ans[0]):
                    ans = (node, dist)
        
        return ans[0]

作者:flix
链接:https://leetcode.cn/problems/find-closest-node-to-given-two-nodes/solution/by-flix-nk4w/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

6135. 图中的最长环

 

class Solution(object):
    def longestCycle(self, edges):
        """
        :type edges: List[int]
        :rtype: int
        """
        import collections
        graph = collections.defaultdict(int)
        for i in range(len(edges)):
            graph[i] = edges[i]
        res = -1
        visited = set()
        for i in range(len(edges)):
            start_node = i
            cur_node = start_node
            # 哈希表记录路径上点到起点的距离
            dist = collections.defaultdict(int)
            d = 0
            while cur_node not in visited:
                visited.add(cur_node)
                dist[cur_node] = d
                d += 1
                cur_node = graph[cur_node]
                if cur_node == -1:
                    break
                if cur_node in dist:
                    pre = dist[cur_node]
                    now = d
                    res = max(res,now - pre)
                    break
        return res

1210. 穿过迷宫的最少移动次数

力扣

class Solution:
    def minimumMoves(self, g: List[List[int]]) -> int:
        step, n = 1, len(g)
        vis = {(0, 0, 0)}
        q = [(0, 0, 0)]  # 初始位置
        while q:
            tmp = q
            q = []
            for X, Y, S in tmp:
                for t in (X + 1, Y, S), (X, Y + 1, S), (X, Y, S ^ 1):  # 直接把移动后的位置算出来
                    x, y, s = t
                    x2, y2 = x + s, y + (s ^ 1)  # 蛇头
                    if x2 < n and y2 < n and t not in vis and \
                       g[x][y] == 0 and g[x2][y2] == 0 and (s == S or g[x + 1][y + 1] == 0):
                        if x == n - 1 and y == n - 2:  # 此时蛇头一定在 (n-1,n-1)
                            return step
                        vis.add(t)
                        q.append(t)
            step += 1
        return -1

作者:endlesscheng
链接:https://leetcode.cn/problems/minimum-moves-to-reach-target-with-rotations/solution/huan-zai-if-elseyi-ge-xun-huan-chu-li-li-tw8b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值