回溯算法,Leetcode 46和Leetcode 980

什么是回溯算法,以及什么时候会用到

回溯算法和递归有关系。它是利用递归来寻找一个问题的所有解,例如一个数组的排列组合所有的可能,还有Leetcode 980题目所说的求出所有可能的路径。

回溯与递归的区别:

递归是函数不断地自己调用自己,直至达到某个零界点后进行层层地返回,最后输出结果。
回溯是利用递归实现的一种算法,在递归的基础上,加上了剪枝的操作,就好比说达到某个条件,就提前返回,不会彻底走完整个递归的过程。还有另外一点就是使用回溯时要记住重置状态,以免影响回溯时下一个分支的结果。

总结一下:

我们可以把递归看作一个 算法结构,而回溯看作一个利用 算法结构 实现的一个 算法思想


接下来我们看两个实例 Leetcode 46和Leetcode 980,一个中等难度和高等难度的题目。
Leetcode 46 全排列:
Leetcode 46 全排列
谈一下解题思路:

输出的结果是全排列,换句话说就是求出所有的解,还记得我们刚刚说过的嘛?要求出一个问题的所有解,就需要用到回溯法,需要借助计算机帮助我们穷举出所有的可能。

现在我们知道了要用回溯来求解,回溯需要用到递归,那么如何来解答这个全排列的问题呢?

我们需要手推一下这个过程再来实现,所有的算法题都是这样哦!

Leetcode官方给的例子我们可以看到,由于有三个元素:1,2,3,答案也被分成了3个部分:1XX,2XX,3XX。
也就是原数组的第一个元素1的位置分别于元素2和3的位置做了一个调换。因此我们可以一直循环这个过程:
1元素和1元素进行调换,2元素和2元素进行调换,3元素和3元素进行调换,结果是数组123本身。
接下来,2元素和3元素进行调换,结果是132。
然后恢复123数组,将1元素和2元素进行调换,接下来最后的两个数字又开始自身和自身调换,然后再交叉互换,分别得到结果213和231。
然后恢复123数组...........
尤其要注意在交换后要恢复123数组本身,不然会产生重复但是又不全的排列组合哦。这一点要自己慢慢体会。因为要让每一个元素都有到第一位的机会,如果不恢复的话就错乱了。

接下来我们可以尝试编程:
对于刚接触的人,可能还是比较不好理解,希望多做题就能感受到吧。我也是这么来的,就是因为不是很理解,所以才通过这种方式让自己记忆更深刻。因为递归中间的过程,是很抽象的。

class Solution(object):
    def permute(self, nums):
        length = len(nums) #数组长度
        res = [] #存放结果的数组
        
        def swap(nums,p,i):
              nums[p],nums[i] = nums[i],nums[p]
        
        def perm(nums, p, q): #p q是用来记录递归子序列的首尾
            #当p==q时,遍历到最底层了子问题只有一个元素了不能进行交换了,就把结果append到res数组中,这里要注意做一个深拷贝,不然会随着后面计算的变化而变化,答案会全部变成一样的结果。
            if p==q:
                temp = [0 for _ in range(0,q)]
                for k in range(0,q):
                    temp[k] = nums[k]
                res.append(temp)

            for i in range(0,q):
                swap(nums,p,i) #交换p和i下标对应的数字
                perm(nums,p+1,q) #对子问题进行全排列
                swap(nums,p,i) #当前组子排列结束后要恢复原来的数组模样
          perm(nums, 0, len(nums))
          return res

Leetcode 980 不同路径III:
Leetcode 980 不同路径III
谈一下解题思路:

这一题与上一题不同,就直接自上而下按逻辑编程就好。我们直接来看一下代码把,具体我会放上注解。
需要注意的还是一些问题处理的小细节,例如如设置走过的路为障碍,递归回上层之前要进行一个障碍的恢复。
具体的结构就是 移动+判断移动是否合法

class Solution(object):
    def uniquePathsIII(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        SPACE = 0
        START = 1
        EXIT = 2
        OBSTACLE = -1
        
        SPACE_COUNT = 0
        
        global PATH_COUNT #要被后面函数用到 记录合法路径数目
        PATH_COUNT = 0
        
        R, C = len(grid),len(grid[0])   
        sr,sc = 0, 0
        
        udlr = ((-1,0)(1,0)(0,-1)(0,1)) #定义上下左右走
        
        
        for r in range(0,R):
            for c in range(0,C):
                #记录有多少个可行走的位置,因为题目要求要走完所有的SPACE
                if grid[r][c] == SPACE:
                    SPACE_COUNT+=1
                #记录起始点
                elif grid[r][c] == START: 
                    sr, sc = r, c
        
        #判断下一步是否合法
        def is_valid_pos(r,c):
            if r < 0 or c < 0:
                return False
            if r < R, c < C:
                return grid[r][c] == SPACE or grid[r][c] == EXIT
            return False
        
        def visit(r,c,visited_count):
            global PATH_COUNT
            #判断递归返回条件
            if grid[r][c] == EXIT:
                if SPACE_COUNT == visited_count:
                    PATH_COUNT+=1
                return #如果走到了EXIT但是没有走满所有的SPACE,就会被返回,路径不加1
            temp = grid[r][c]
            grid[r][c] = OBSTACLE
            for dr,dc in udlr:
                nextr,nextc = r+dr,c+dc
                if is_valid_pos(nextr,nextc):
                    visit(nextr,nextc,visited_count+1)
            grid[r][c] = temp
        
        visit(sr,sc,0)
        return PATH_COUNT
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容