Backtrack 算法思路

Backtrack 算法思路

1.引言

黄色的树林里分出两条路,可惜我不能同时去涉足,我选择了人迹稀少的一条,从此决定了我一生的道路

2.什么是回溯算法?

Backtrack算法,中译回溯算法,是一个非常实用的一个算法,如果用一个谚语来形容回溯算法,我愿意称之为“不撞南墙不回头”的一种算法。

为什么这么说呢?因为回溯算法实质上就是一种不断尝试,通过不断的“试错”不断更改信息的一种算法。

“不撞南墙”说明了当回溯算法不遇到错误的时候,“不回头”就是不返回上一步重新尝试。

从引言的那首罗伯特.弗罗斯特的诗里,“可惜我不能同时去涉足”,可是对于回溯算法来说不是这样的,回溯算法看到路走错了就不会继续走了,它会折返到最近的一个分岔口,重新选择一条道路行走。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FIvQYVnT-1652531632747)(https://tse1-mm.cn.bing.net/th/id/R-C.91867e276501f596a4802b67aea756f6?rik=T2H1qdJZGAQe7g&riu=http%3a%2f%2fimg95.699pic.com%2fphoto%2f50123%2f6755.jpg_wh300.jpg!%2ffh%2f300%2fquality%2f90&ehk=6ZJzrS%2bT3A%2fCApII9W0nWQRrSgaCGaU1C3o6wI7aRLs%3d&risl=&pid=ImgRaw&r=0&sres=1&sresct=1)]

回溯算法可以用来解数独,进行排列组合,解决N皇后等问题

3.回溯算法的实现

让我们来看一看79. 单词搜索 这道题

这道题要求我们从board里面查找某一个单词(例如:ABCDE),如果查找到单词,我们就返回True,否则返回False。

单词搜索

如上所示,黄色的路径就代表我们成功找到了“ABCDE”这个连续的单词。我们可以从上、下、左、右四个方向进行单词查找。

这里有一点需要注意,单词并不需要第一行第一列的数字来开始,我们可以从任何点上开始单词。

回溯算法的基本思路

1.确定Base case,即考虑一些越界情况,结果实现的情况。

2.在选择列表中进行选择

3.迭代下一个情况

4.撤销选择

这个回溯算法可以如下定义:

def backtrack(x,y,index)

x,y就是我们传进去的board的行数和列数,index为单词的索引

def dfs(x,y,index):
            #base case
        
            if x<0 or x>=row or y<0 or y>=col:return False
            if board[x][y]!=word[index]:
                return False
            if index ==len(word)-1:
                return True
            
            #做选择

            board[x][y] = '#' 
            
            #进行迭代
            
            for i in [[0,1],[1,0],[0,-1],[-1,0]]:
                next_x = x+i[0]
                next_y = y+i[1]
                if dfs(next_x,next_y,index+1):
                    return True

                    
            #撤销选择
            
            board[x][y] = word[index]

            return False
        
            #开始点,可以从任一行任一列开始
            
        for i in range(row):
            for j in range(col):
                if dfs(i,j,0):
                    return True

        return False

如上,按照思路,第一步:确立Base case,当索引为index的单词字符刚刚和board的x行y列的字符相同时,继续走下去,如果不是,则return,程序返回上一步(即返回上一次for循环,进行下一个循环),如果继续走下去,就再次执行刚刚的内容,如此循环,直至我们可以找到一个序列和给出的单词一致,即index的长度达到了单词的长度。

让我们来看下一道一个比较简单的题目, 全排列

输入:nums = [1,2,3]

输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

代码如下:

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        track = []
        def backtrack():
            if len(track) == len(nums): #base case
                res.append(track[:])
                return
            
            for i in range(0,len(nums)):
                if nums[i] in track:
                    continue

                track.append(nums[i]) #选择
                backtrack() #迭代
                track.pop()#撤销选择
                
        backtrack()
        return res

还是惯常的思路,确立一个Base case,然后进行选择,进行迭代,撤销选择。

其实从回溯算法里面,我们也能发现一件事,那就是所谓“智能”的计算机,实际上是因为计算机拥有巨大的“计算能力",它能不厌其烦的进行大量的数据处理,并从这些数据中根据我们所确立的“basecase”进行选择。

如果你跟一个不知道计算机怎么运行的人演示这个全排列算法(如果你去演示一个N皇后,解数独的例子可能更好),他们会纠结于为什么你跟电脑说:“给我一个数组[1,2,3]的全排列输出。”电脑就会如实的做到,电脑他难道是因为知道全排列的含义而去思考吗?实际上是你给他一个指令,让他去遍历这些数组组成的所有有用序列,然后返回而已。

不过,这样也可以说明,电脑是可以拥有“学习能力”的,比如你给计算机一百万个数据,让他去处理这之间的关系(而不需要你告诉它关系是什么),然后你再丢给它一个不是数据里数字,他能返回给你一个“最接近结果”的一个值,当然,这就是另一种事情了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值