算法工程师必知必会的10大基础算法与python示例(二)

本文介绍了深度优先搜索(DFS)和广度优先搜索(BFS)两种图算法,分别通过LeetCode实例进行解析。DFS适用于二叉树遍历,而BFS常用于寻找无权图的最短路径。此外,还提到了Dijkstra算法解决带权有向图的单源最短路径问题以及动态规划和朴素贝叶斯分类算法的基本概念。
摘要由CSDN通过智能技术生成


写在一起太长了,分两部分,第二部分放这~~~

算法六:深度优先搜索(DFS)

深度优先搜索(depth first search),是图搜索算法的一种,它会沿着图的某一条路径穷尽遍历,然后再回溯,到之前的vertex去遍历其他的路径。这种算法在一个特殊的图-----二叉树中用的比较多。以二叉树距离,DFS即从根节点出发,穷尽某条路径,直到叶节点,再回溯其父节点,穷尽该父节点的其他子节点。重复这个过程,知道遍历整个树,或者找到目标节点。
DFS属于盲目搜索。DFS是图论中的经典算法,利用DFS产生的目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题。

DFS算法步骤如下:

  1. 访问节点v。
  2. 一次从v的未访问节点出发,对图进行深度优先遍历,直至途中和v有路径相通的定点都被访问。
  3. 若此时途中尚有未被访问的顶点,则从一个未被访问的定点出发,重新进行深度优先遍历,直至途中所有的顶点均被访问。

比较经典的深度有点遍历例子就是数的先序(中序、后续)遍历,采用递归策略,代码如下:

'''
class Node:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
'''
class Solution:
    def DFS(self, root):
        if not root:
            return
        print(root.val) #先序遍历
        self.DFS(root.left)
        #print(root.val) #中序遍历
        self.DFS(root.right)
        #print(root.val) #后续遍历

一般作为辅助手段,我们这里举leecode中的一个有意思的题,作为例子

leetcode例子

这是个序列化反序列化二叉树的例子,深度优先遍历这种递归解法很是优雅,贴在这里仅供观赏。

'''
297. 二叉树的序列化与反序列化
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

示例: 

你可以将以下二叉树:

    1
   / \
  2   3
     / \
    4   5

序列化为 "[1,2,3,null,null,4,5]"
'''

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Codec:


    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        def recurse_first(root):
            if not root:
                return ',null'
            else:
                return ','+str(root.val) +recurse_first(root.left)+recurse_first(root.right)
               
        re = recurse_first(root)
        return re[1:]


        

    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        data = data.split(',')
        def recurse_first(ind):
            if data[ind] == 'null':
                return ind, None
            else:
                root = TreeNode(data[ind])
                l, left = recurse_first(ind + 1)
                root.left = left
                r, right = recurse_first(l + 1)
                root.right = right
                return r, root
        return recurse_first(0)[1]

算法七:广度优先搜索(BFS)

说完DFS不得不说一下BSF,BFS是广度优先搜索(breadth first search)。这也是一种图所搜算法,不过与DFS不同的是,这种算法不是沿着一条路径穷尽再回溯,而是直接将vertex的临近节点穷尽,再穷尽临近节点的临近节点,知道遍历完整个图或者找到目标图位置。BFS一般用于找寻无权图的最优路径,一般情况下用一个队列来辅助,队列是FIFO的。
DFS的算法步骤如下:

  1. 首先将原点放入队列。
  2. 循环,当队列非空时,从队列中pop出一个节点,将该节点标记为已访问,然后将这个节点的所有临近节点全部压入队列。
  3. 再循环过程中,如果遇到目标节点,退出循环。队列为空,退出循环,意味着与原点联通的节点全部遍历完毕。

leetcode例子

无权图的话,是可以用bfs找最短路径的。leetcode上面有一个有意思的题,直接上吧

'''
给你一个 m x n 的网格图 grid 。 grid 中每个格子都有一个数字,对应着从该格子出发下一步走的方向。 grid[i][j] 中的数字可能为以下几种情况:

1 ,下一步往右走,也就是你会从 grid[i][j] 走到 grid[i][j + 1]
2 ,下一步往左走,也就是你会从 grid[i][j] 走到 grid[i][j - 1]
3 ,下一步往下走,也就是你会从 grid[i][j] 走到 grid[i + 1][j]
4 ,下一步往上走,也就是你会从 grid[i][j] 走到 grid[i - 1][j]
注意网格图中可能会有 无效数字 ,因为它们可能指向 grid 以外的区域。

一开始,你会从最左上角的格子 (0,0) 出发。我们定义一条 有效路径 为从格子 (0,0) 出发,每一步都顺着数字对应方向走,最终在最右下角的格子 (m - 1, n - 1) 结束的路径。有效路径 不需要是最短路径 。

你可以花费 cost = 1 的代价修改一个格子中的数字,但每个格子中的数字 只能修改一次 。

请你返回让网格图至少有一条有效路径的最小代价。

 

示例 1:



输入:grid = [[1,1,1,1],[2,2,2,2],[1,1,1,1],[2,2,2,2]]
输出:3
解释:你将从点 (0, 0) 出发。
到达 (3, 3) 的路径为: (0, 0) --> (0, 1) --> (0, 2) --> (0, 3) 花费代价 cost = 1 使方向向下 --> (1, 3) --> (1, 2) --> (1, 1) --> (1, 0) 花费代价 cost = 1 使方向向下 --> (2, 0) --> (2, 1) --> (2, 2) --> (2, 3) 花费代价 cost = 1 使方向向下 --> (3, 3)
总花费为 cost = 3.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-cost-to-make-at-least-one-valid-path-in-a-grid
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
'''

class Solution:
    def minCost(self, grid: List[List[int]]) -> int:
        dx = [0, 0, 1, -1]
        dy = [1, -1, 0, 0]

        import queue
        store = queue.Queue()
        dis = [[100000000 for i in range(len(grid[0]))] for j in range(len(grid))]
        store.put([0, 0])
        dis[0][0] = 0
        while not store.empty():
            [x, y] = store.get()
            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if nx<0 or nx>=len(grid) or ny<0 or ny>=len(grid[0]):
                    continue
                new_dis = dis[x][y] + 0 if i+1 == grid[x][y] else dis[x][y] + 1
                if new_dis<dis[nx][ny]:
                    dis[nx][ny] = new_dis
                    store.put([nx, ny])
        return dis[len(grid)-1][len(grid[0])-1]
if __name__ == '__main__':
    solution = Solution()
    grid = [[1,1,1,1],[2,2,2,2],[1,1,1,1],[2,2,2,2]]
    print(solution.minCost(grid))

算法八:狄克斯特拉算法(Dijkstra)

bfs可以解决无权图最短路径问题。可是,在实际工程过程中,边带权重的图才更加广泛。嗯,带权图的最短路径算法狄克斯特拉算法应运而生。该算法由荷兰计算机科学家狄克斯特拉提出。

Dijkstra算法使用广度优先搜索思路来解决非负有权有向的单源最短路径问题,算法最终得到一个最短路径树。该算法的输入包含了一个有权重的有向图 G G G以及 G G G中的一个来源顶点 S S S,我们用 V V V标识 G G G中的所有顶点的集合。

图都是加权有向的,所以表示起来稍微麻烦些。用有序数对 ( u , v ) (u, v) (u,v)表示从顶点 U U U到顶点 V V V有路径连接,我们用 E E E表示 G G G中的所有边的集合,而边的权重则有权重函数 w : E → [ 0 , ∞ ) w:E\to[0, \infty) w:E[0,)定义,即用数组 w ( u , v ) w(u, v) w(u,v)表示有向路径 ( u , v ) (u, v) (u,v)的非负权重。

狄克斯特拉算法用于在单源有向图中寻找源点到其他顶点的最短路径。对于不含负权的有向图,狄克斯特拉算法是目前已知的最快的单源最短路径算法。

狄克斯特拉算法如下:

1.初始时,令 S =

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值