算法学习(十一)

学习内容:

优先搜索算法:包括深度优先搜索和广度优先搜索;深度优先搜索(DFS):在搜索到一个新节点时,立即对该新节点进行遍历;因此遍历需要用先入后出的栈来实现,也可以通过与栈等价的递归来实现;广度优先搜索(BFS):一层层进行遍历,需要用先入先出的队列进行遍历。

学习产出:

广度优先搜索

广度优先搜索

不同于深度优先搜索,他是一层层进行遍历,需要用先入先出的队列进行遍历。由于是按层次进行遍历,广度优先搜索按照“广”的方向进行遍历,常用来处理最短路径问题

LeetCode 934 最短的桥

在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)

现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。

返回必须翻转的 0 的最小数目。(可以保证答案至少是 1。)

示例 1:

输入:[[0,1],[1,0]]
输出:1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-bridge
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
         

题解

实际求解两个岛最短路径问题,可使用任意搜索方法找到其中一个岛,然后广度优先搜索,求于另一个岛的最短距离

代码(python)

class Solution:
    def shortestBridge(self, A: List[List[int]]) -> int:
        direction = [-1,0,1,0,-1] #方位列表
        m,n = len(A),len(A[0]) #行、列
        points = [] #初始化队
        flipped = False #标记
        def dfs(points, grid,i,j): #深度优先搜索搜索第一个岛
            if i<0 or j<0 or i==m or j==n or grid[i][j] ==2:
                return
            if grid[i][j] == 0:
                points.append([i,j]) #海面位置写入
                return
            grid[i][j] = 2
            dfs(points, grid, i - 1, j)
            dfs(points, grid, i + 1, j)
            dfs(points, grid, i, j - 1)
            dfs(points, grid, i, j + 1)
    	#dfs寻找第一个岛屿
        for i in range(m):
            if flipped : break
            for j in range(n):
                if A[i][j] == 1:
                    dfs(points,A,i,j)
                    flipped = True
                    break
    	#bfs寻找第二岛屿
        level = 0 
        while points:
            level += 1 #造陆次数统计
            n_points = len(points)
            while n_points:
                [r,c]=points.pop(0) #出队
                for k in range(4):
                    x = r+direction[k]
                    y = c+direction[k+1]
                    if x>=0 and y>=0 and x<m and y<n:
                        if A[x][y] == 2:
                            continue
                        if A[x][y] == 1:
                            print(points)
                            return level
                        points.append([x,y])
                        A[x][y] = 2 
                n_points -= 1
    			

LeetCode 126 单词接龙 II

给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:

每次转换只能改变一个字母。
转换后得到的单词必须是字典中的单词。
说明:

如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同

示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出:
[
  ["hit","hot","dot","dog","cog"],
  ["hit","hot","lot","log","cog"]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-ladder-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。      
    

题解

把起始字符串,终止字符串,以及单词表里所有字符串想象成节点,如果两个字符串只有一个字符不同,那它们相连。因为题目要求输出修改次数最少的所有修改方式,所以可以使用广度优先搜索,求起始点到终止点的最短距离。同时采用两端搜索即从起始点和终止点分别进行搜索,每次只延展当前层节点数最少的那一端,这样可以减少搜索的总节点数。在结束后,还需要回溯重建所有可能的路径。

代码(python)

class Solution:
    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        path = [] #回溯路径
        ans = [] #结果
        dict = wordList 
        if  not dict.count(endWord): #不存在结束字符直接结束
            return ans
        #删除字典里的开始和结束字符
        if beginWord in dict:
            dict.remove(beginWord)
        if endWord in dict:
            dict.remove(endWord)
        q1,q2=[beginWord], [endWord]
        revers,found = False,False #标记
        next = collections.defaultdict(list) #初始化字典用于记录遍历流程
        def backtracking(src,dst,next,path,ans): #回溯算法
            if src == dst:
                ans.append(path[:])
                return
            for s in  next[src]:
                path.append(s) #修改当前节点
                backtracking(s,dst,next,path,ans) #递归子节点
                path.pop() #回改当前节点
        #修改起始字符寻找字典有的词
        while q1!=[]:
            q = []
            for i in range(len(q1)): 
                w = q1[i]
                s = list(q1[i])
                for i in range(len(s)): #遍历字符每一位
                    ch = s[i]
                    for j in range(26):
                        s[i] = chr(j+ ord('a')) 
                        s1 = ''.join(s)
                        #遍历搜索满足条件的单词,并保存在next字典中
                        if  q2.count(s1):
                            if revers:
                                next[s1].append(w)
                            else: next[w].append(s1)
                            found = True
                        if dict.count(s1):
                            if revers:
                                next[s1].append(w)
                            else: next[w].append(s1)
                            q.append(s1)
                    s[i] = ch
            if found:
                break
            for i in range(len(q)):
                if q[i] in dict: #删除已经遍历的单词
                    dict.remove(q[i])
            if len(q) <= len(q2):
                q1 = q
            else:
                revers = not revers
                q1 = q2
                q2 = q
        if found:
            path=[beginWord]
            backtracking(beginWord,endWord,next,path,ans)
        return  ans

注:结果正确,但是与力扣的结果,在排序位置有所不同,有待改进结果,插个眼记一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值