碎碎念: 最近终于开始刷middle的题了,对于我这个小渣渣确实有点难度,经常一两个小时写出一道题来。在开始写的几道题中,发现大神在discuss中用到回溯法(Backtracking)的概率明显增大。感觉如果要顺利的把题刷下去,必须先要把做的几道题题总结一下。


先放上参考的web:

  1. https://segmentfault.com/a/1190000006121957
  2. http://summerisgreen.com/blog/2017-07-07-2017-07-07-算法技巧-backtracking.html
  3. http://www.leetcode.com

回溯法是什么

回溯法跟DFS(深度优先搜索)的思想几乎一致,过程都是穷举所有可能的情况。前者是一种找路方法,搜索的时候走不通就回头换条路继续走,后者是一种开路策略,就是一条道先走到头,再往回走移步换一条路都走到头,直到所有路都被走遍。

既然说了,这是一种穷举法,也就是把所有的结果都列出来,那么这就基本上跟最优的方法背道而驰,至少时间复杂度是这样。但是不排除只能用这种方法解决的题目。

不过,该方法跟暴力(brute force)还是有一点区别的,至少动了脑子。

回溯法通常用递归实现,因为换条路继续走的时候换的那条路又是一条新的子路。

回溯法何时用

高人说,如果你发现问题如果不穷举一下就没办法知道答案,就可以用回溯了。

一般回溯问题分三种:

  1. Find a path to success 有没有解
  2. Find all paths to success 求所有解
    • 求所有解的个数
    • 求所有解的具体信息

3.Find the best path to success 求最优解

理解回溯:

回溯可以抽象为一棵树,我们的目标可以是找这个树有没有good leaf,也可以是问有多少个good leaf,也可以是找这些good leaf都在哪,也可以问哪个good leaf最好,分别对应上面所说回溯的问题分类。

回溯问题解决

有了之前对三个问题的分类,接下来就分别看看每个问题的初步解决方案。

有没有解

boolean solve(Node n) {
if n is a leaf node {
if the leaf is a goal node, return true
else return false
} else {
for each child c of n {
if solve(c) succeeds, return true
}
return false
}
}

这是一个典型的DFS的解决方案,目的只在于遍历所有的情况,如果有满足条件的情况则返回True

求所有解的个数

void solve(Node n) {
if n is a leaf node {
if the leaf is a goal node, count++, return;
else return
} else {
for each child c of n {
solve(c)
}
}
}

列举所有解

这是文章的重点:

sol = []
def find_all(s, index, path, sol):
if leaf node: ## (via index)
if satisfy?(path):
sol.append(path)
return
else:
for c in choice():
find_all(s[..:..], ,index+/-1, path+c, sol)

对于寻找存在的所有解的问题,一般不仅需要找到所有解,还要求找到的解不能重复。

这样看着思路虽然简单,但是在实际运用过程中需要根据题目进行改动,下面举一个例子:

eg1: 18. 4Sum

Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:

[

[-1, 0, 0, 1],

[-2, -1, 1, 2],

[-2, 0, 0, 2]

]

下面的代码就是一个实际的回溯操作。

这个回溯函数有5个参数,nums是剩余数据,target是需要达到的条件,N为每层的遍历次数。

result当前处理的结果。results为全局结果。

这是一个典型的python解法,之后很多题都是套这个模版,我发现。

def fourSum(self, nums, target):
def findNsum(nums, target, N, result, results):
if len(nums) < N or N < 2 or target < nums[0]*N or target > nums[-1]*N: # early termination
return
if N == 2: # two pointers solve sorted 2-sum problem
l,r = 0,len(nums)-1
while l < r:
s = nums[l] + nums[r]
if s == target:
results.append(result + [nums[l], nums[r]])
l += 1
while l < r and nums[l] == nums[l-1]:
l += 1
elif s < target:
l += 1
else:
r -= 1
else: # recursively reduce N
for i in range(len(nums)-N+1):
if i == 0 or (i > 0 and nums[i-1] != nums[i]):
findNsum(nums[i+1:], target-nums[i], N-1, result+[nums[i]], results) results = []
findNsum(sorted(nums), target, 4, [], results)
return results

第一个if为初始条件判断。

第二个if判断是否为叶结点,且是否满足条件

else后面是对于非叶结点

[Leetcode] Backtracking回溯法解题思路的更多相关文章

  1. Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III)

    Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III) 同类题目: Leetcode之回溯法专题-39. 组合总数(Combination Sum) Lee ...

  2. Leetcode之回溯法专题-212. 单词搜索 II(Word Search II)

    Leetcode之回溯法专题-212. 单词搜索 II(Word Search II) 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单 ...

  3. Leetcode之回溯法专题-131. 分割回文串(Palindrome Partitioning)

    Leetcode之回溯法专题-131. 分割回文串(Palindrome Partitioning) 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回 s 所有可能的分割方案. ...

  4. Leetcode之回溯法专题-90. 子集 II(Subsets II)

    Leetcode之回溯法专题-90. 子集 II(Subsets II) 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入 ...

  5. Leetcode之回溯法专题-79. 单词搜索(Word Search)

    Leetcode之回溯法专题-79. 单词搜索(Word Search) 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元 ...

  6. Leetcode之回溯法专题-78. 子集(Subsets)

    Leetcode之回溯法专题-78. 子集(Subsets) 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums = ...

  7. Leetcode之回溯法专题-77. 组合(Combinations)

    Leetcode之回溯法专题-77. 组合(Combinations)   给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合. 示例: 输入: n = 4, k = 2 输 ...

  8. Leetcode之回溯法专题-52. N皇后 II(N-Queens II)

    Leetcode之回溯法专题-52. N皇后 II(N-Queens II) 与51题的代码80%一样,只不过52要求解的数量,51求具体解,点击进入51 class Solution { int a ...

  9. Leetcode之回溯法专题-51. N皇后(N-Queens)

    Leetcode之回溯法专题-51. N皇后(N-Queens) n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给 ...

随机推荐

  1. 2018年第九届蓝桥杯【C++省赛B组】

    2标题:明码 汉字的字形存在于字库中,即便在今天,16点阵的字库也仍然使用广泛.16点阵的字库把每个汉字看成是16x16个像素信息.并把这些信息记录在字节中. 一个字节可以存储8位信息,用32个字节就 ...

  2. 第九次作业psp

    psp 进度条 代码累积折线图 博文累积折线图 psp饼状图

  3. Scrum Meeting 13 -2014.11.19

    最近数据库和编译的实验课也开始了,大家晚上的时间直接被砍掉了大部分. 希望大家能顺利完成项目吧.剩下时间也不多了,如果程序还存在一些特别的问题和需要优化修改的地方也应该考虑留到下阶段进行了. Memb ...

  4. 31_网络编程(Socket套接字编程)_讲义

    今日内容介绍 1.网络三要素及传输协议 2.实现UDP协议的发送端和接收端 3.实现TCP协议的客户端和服务器 4.TCP上传文件案例 01网络模型 *A:网络模型 TCP/IP协议中的四层分别是应用 ...

  5. 树莓派与Arduino Leonardo使用NRF24L01无线模块通信之基于RF24库 (三) 全双工通信

    设计思路 Arduino Leonardo初始化为发送模式,发送完成后,立即切换为接收模式,不停的监听,收到数据后立即切换为发送模式,若超过一定时间还为接收到数据,则切换为发送模式. 树莓派初始化为接 ...

  6. iOS开发短信验证码封装 方便好用

    ---恢复内容开始--- 1.RootViewControler//  Copyright © 2016年 Chason. All rights reserved.// #import "V ...

  7. React---点击按钮实现内容复制功能

    思路: 1.给要复制的内容容器添加一个标签(可以是ID,可以是类名等),通过dom技术获取该容器对象: 2.创建Range对象(某个区域内连续的内容),把该容器对象放进去: 3.将Range对象添加到 ...

  8. contos7忘记root密码怎么办

    首先在这个界面按"e"键 然后呢就会进入到如下图所示的界面,在LANG=zh_CN.UTF8的后面加上 init=/bin/sh, 再按 [ Ctrl + X ] 进入'单用户模式 ...

  9. sublimeText3的一些操作记录

    # 给绿色版的sublimeText3添加右键菜单,其中@=“Sublime Text 3” 是右键展示的文字, 后面的icon是图标将下面代码保存为.reg文件执行 Windows Registry ...

  10. java中的==操作符和equals函数

    基本规则 “==”操作符的使用需要分成两种情况 判值类型相等 这一点很好理解,两个值类型代表的数值相等,则“==”表达式返回true “==”可以用与不同值类型的比较,语言会自动进行类型转换 判引用类 ...