为什么对于回溯,有时我们需要在递归后显式弹出,有时则不需要?

2023-12-05

例如,让我们考虑一个任务,我们需要找到给定字符串的所有排列,保留字符序列但改变大小写。

这是没有回溯的解决方案.pop():

def letterCasePermutation(S):
    """
    :type S: str
    :rtype: List[str]
    """
    def backtrack(sub="", i=0):
        if len(sub) == len(S):
            res.append(sub)
        else:
            if S[i].isalpha():
                backtrack(sub + S[i].swapcase(), i + 1)
            backtrack(sub + S[i], i + 1)
            
    res = []
    backtrack()
    return res

这是一个解决方案.pop():

def letterCasePermutation(s):
    def backtrack(idx, path):
        if idx == n:
            res.append("".join(path))
            return
        
        ele = s[idx]
        if ele.isnumeric():
            path.append(ele)
            backtrack(idx + 1, path)
            path.pop()
        else:
            path.append(ele.lower())
            backtrack(idx + 1, path)
            path.pop()
            path.append(ele.upper())
            backtrack(idx + 1, path)
            path.pop()
            
    n = len(s)
    res = []
    backtrack(0, [])
    return res

两个代码示例都是回溯,还是应该将第一个代码示例称为 DFS,将第二个代码示例称为回溯?


对于回溯(以及大多数递归函数),每个函数调用的关键不变量是它不会破坏父调用中的状态。

这应该具有直观意义,因为递归依赖于自相似性。如果调用堆栈中其他地方发生不可预测的状态更改,从而影响与祖先调用共享的数据结构,则很容易看出自相似性的属性是如何丢失的。

递归函数调用通过将框架推到调用栈,根据需要在本地操作状态,然后弹出调用堆栈。在返回父框架之前,子调用负责恢复状态,以便从父调用框架的角度来看,执行可以继续进行,而不会被链上的某个随机祖先调用造成任何令人惊讶的状态修改。

打个比喻,您可以将每个调用帧视为遍历以下情节帽子里的猫 or 冒险生意如果主角弄乱了(在他们的调用框架中),那么必须在故事结束(函数返回)之前恢复秩序。

现在,鉴于这个高级目标,如您的代码片段所示,有多种方法可以实现它。一种方法是分配某种数据结构,例如列表对象一次,然后push (append) and pop在每个调用帧上,镜像调用堆栈。

另一种方法是在生成子调用时复制状态,以便每个帧接收相关数据的最新版本,并且它们所做的任何修改都不会扰乱其父状态。与改变单个数据结构相比,这通常需要更少的簿记,并且不太容易受到细微错误的影响,但由于内存分配器和垃圾收集器操作以及为每个帧复制数据结构,往往会产生更高的开销。

简而言之,不要混淆保持每个调用帧状态完整的高级目标和代码如何实现它。


据,直到...为止回溯 versus DFS,我认为回溯是一种专门的 DFS,它会修剪掉启发式确定不值得进一步探索的搜索树分支,因为它们无法得出解决方案。和以前一样,代码如何实际实现状态恢复以实现回溯(复制数据结构或推送/弹出显式堆栈)不应改变它是相同基本算法技术的事实。

我见过术语“回溯”应用于这样的排列算法。尽管该术语可能相当常见,但它似乎是一种误用,因为排列算法是一种全状态递归遍历,它将始终访问树中的所有节点,并且不会像回溯那样进行任何智能启发式修剪。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么对于回溯,有时我们需要在递归后显式弹出,有时则不需要? 的相关文章

  • 如何返回n对括号的所有有效组合?

    def paren n lst for x in range n current string join lst solutions list for i in range len current string 1 close curren
  • 如何从一组重叠的圆计算多边形集?

    这个问题是一些计算细节的扩展这个问题 https stackoverflow com questions 1667310 combined area of overlapping circles 假设有一组 可能重叠的 圆 并且希望计算这组
  • 删除队列中的最后一个元素

    我需要删除队列的最后一个元素 我唯一可以使用的操作是 Peek 获取第一个元素而不删除它 Enqueue element 向队列末尾插入一个元素 Dequeue 删除第一个元素 IsEmpty true 或 false 队列是否为空 而且我
  • 如何确定算法函数的复杂度?

    您如何知道算法函数对于特定操作是否需要线性 常数 对数时间 它取决于CPU周期吗 您可以通过三种方式 至少 做到这一点 在网上查找算法 看看它是如何描述其时间复杂度的 根据输入大小 自己检查算法 查看嵌套循环和递归条件等内容 以及每个循环运
  • 最慢的计算复杂度(Big-O)

    在这些算法中 我知道 Alg1 是最快的 因为它是 n 平方的 接下来是 Alg4 因为它是 n 的立方 然后 Alg2 可能是最慢的 因为它是 2 n 这应该具有非常差的性能 然而Alg3和Alg5在我的阅读速度方面还没有遇到过 这两种算
  • 解释一下从 N 个给定集合中的每一个中给出第 K 个最大数字的示例?

    今天我尝试解决一个Facebook 编程挑战赛 https facebook interviewstreet com recruit challenges 我遇到的挑战是 酒吧问题 可以找到here https github com alo
  • 如何求小于给定数的最大2次方

    我需要找到小于给定数字的最大 2 次幂 我陷入困境 找不到任何解决方案 Code public class MathPow public int largestPowerOf2 int n int res 2 while res lt n
  • 寻找将集合映射到整数的双射函数

    对于任意两个序列 a b 其中 a a1 a2 an 且 b b1 b2 bn 0a b具有相同的元素 而不关心它们的顺序 例如 如果 a 1 1 2 3 b 2 1 3 1 c 3 2 1 3 则 f a f b f a f b 我知道有
  • 从三点求圆心的算法是什么?

    我在圆的圆周上有三个点 pt A A x A y pt B B x B y pt C C x C y 如何计算圆心 在Processing Java 中实现它 我找到了答案并实施了一个可行的解决方案 pt circleCenter pt A
  • 关于在字典中查找所有有效单词的算法问题

    给定一个字典 只是一个字符串列表 您收到来自外部来源的未知数量的信件 给定字母串 您将如何列出您可以通过这些字母的任意组合组成的所有有效单词 来自字典 因此 如果您收到 applead 你应该找到apple bad pad lead等 我知
  • 分而治之策略来确定列表中是否有超过 1/3 的相同元素

    我正在使用分治算法来确定列表中是否有超过 1 3 的元素相同 例如 1 2 3 4 不 所有元素都是唯一的 1 1 2 4 5 是的 其中 2 个是相同的 没有排序 是否有分而治之的策略 我陷入了如何划分的困境 def is valid i
  • 在常数空间中创建 1..N 的随机排列

    我正在寻找枚举固定空间中数字 1 N 的随机排列 这意味着我无法将所有数字存储在列表中 原因是 N 可能非常大 超过可用内存 我仍然希望能够一次遍历这样一个数字的排列 只访问每个数字一次 我知道对于某些 N 可以这样做 许多随机数生成器随机
  • 绘制多边形

    我正在使用 Google Maps API V3 根据路径绘制多边形 该路径是随机未排序坐标点 LatLng 的数组 这会产生以下形状 Polylines intersect Problem 由于多边形的形状取决于路径中点的顺序 因此如何对
  • 找到一条穿过任意节点序列的最短路径?

    In 这个先前的问题 https stackoverflow com questions 7314333 find shortest path from vertex u to v passing through a vertex wOP询
  • 如何从迭代器推导连续内存

    不知何故 本土stl copy VC Dinkumware 上的算法表明它可以使用memcpy 可以轻松复制的数据 一个凡人能做到这一点吗 假设每个元素都是普通可复制的 random access iterator 是否意味着连续内存 标准
  • 从一种数字系统转换为另一种数字系统后会有多少位数字

    主要问题 有多少位数字 让我解释 我有一个二进制数 11000000 十进制数是192 转换为十进制后 它有多少位 以十进制表示 在我的示例中 它是 3 位数字 但是 这不是问题 我在互联网上搜索并找到了一种用于整数部分的算法和一种用于小数
  • n 或 nlog(n) 比常数时间或对数时间更好吗?

    在 Coursera 上的普林斯顿教程中 讲师解释了遇到的常见增长顺序函数 他说 线性和线性算术运行时间是 我们努力的目标 他的推理是 随着输入大小的增加 运行时间也会增加 我认为这是他犯了错误的地方 因为我之前听过他提到线性增长顺序对于高
  • 照片马赛克算法。如何在给定基本图像和瓷砖列表的情况下创建马赛克照片?

    Hy 我要做的是创建一个程序 使用 C 或 C 它将 24 位 像素位图和图像集合作为输入 我必须创建一个马赛克图像 类似于使用库的输入图像给定的图像 创建与输入类似的马赛克照片 到目前为止 我可以访问输入的图像像素及其颜色 但我有点卡住了
  • O(1) 算法确定节点是否是多路树中另一个节点的后代?

    想象一下下面的树 A B C D E F 我正在寻找一种方法来查询 F 是否是 A 的后代 注意 F 不需要是directA 的后代 在这种特殊情况下这是正确的 只需要针对更大的潜在后代节点池测试有限数量的潜在父节点 当测试一个节点是否是潜
  • 归并排序中的递归:两次递归调用

    private void mergesort int low int high line 1 if low lt high line 2 int middle low high 2 line 3 mergesort low middle l

随机推荐

  • 维基百科 API 是否支持 CORS 还是仅支持 JSONP?

    这个问题涉及到另一个问题 这是一年前问过的 作者询问如何使用 JavaScript 和 Wikipedia API 发出跨域请求 一条评论是 en wikipedia org 似乎不允许 CORS 建议他改用 JSONP 我知道我可以使用
  • 动态更新fabric.js路径点

    我正在尝试动态地将点添加到路径对象 当我这样做时 路径会正确渲染 但边界矩形永远不会更新 这使得用户几乎不可能在画布上选择和移动路径 正如您在下面的代码中看到的 路径最初是使用单个点创建的 然后我动态添加第二个点以及控制点 执行此操作后 边
  • 如何使用 Apache POI 将 docx 中的文本(标签)替换为 HTML?

    我们将有一些模板 docx 文件 其中会有一些标签 例如 content 我需要用 HTML 替换这个标签 为此 我想在 XWPFDocument 中使用 altChunk 元素 以下答案在如何使用 Apache POI 将 altChun
  • 使用逗号格式化数字字符串

    我想格式化数字 我见过一些在数字字符串中插入逗号的正则表达式示例 都是连续检查3位数字 然后在数字中插入逗号 但我想要这样的东西 122 as 122 1234 as 1 234 12345 as 12 345 1723456 as 17
  • C 匹配组中的正则表达式

    我一直在努力解决 C 中的正则表达式 只是 usr include regex h 我有 比方说 数百个正则表达式 其中之一可以匹配输入字符串 目前我正在这样做 实际上生成它 如下所示 数百个 do while 内部有匹配 如果不匹配则中断
  • Hibernate多对多,重复相同的记录

    我尝试使用注释进行 Hibernate 映射多对多 并使用 vaannila 中给出的示例 http www vaannila com hibernate hibernate example hibernate mapping many t
  • 更新另一个视图上的标签

    我有两个视图 其中一个带有标签 在第二个视图上 有一个按钮 我想在这里实现的是能够按下按钮并更新第一个视图上的标签 我怎么做 我无法从第二个视图访问 IBOutlet 我必须对 IBOutlet 做些什么才能将其公开等吗 您可以使用NSNo
  • 如何在C#中的dll中进行全局异常处理?

    Dll 在 C 中没有入口点 因此我需要将全局异常处理的代码放在一处 因为这些 dll 在 exe 中引用 并且所有 dll 都有 try catch 但存在一些错误 导致它崩溃并识别我们正在尝试创建故障转储 任何人都可以建议这是可行的解决
  • 使用 HttpClient 发布自定义类型

    我有一个自定义 dto 类 public class myObject public string Id get set public string Name get set 和使用 Web Api 的控制器 4 5 net 框架 Http
  • 如何在 C 函数内使用全局结构引用填充结构指针?

    我是 C 新手 无法理解为什么 my struct ptr main 在下面的示例中为零 如何将 my structs 数组中结构的地址分配给 get my struct by name 函数中的 my struct ptr 指针 stru
  • Python 中根据条件求和嵌套列表

    我有一个嵌套列表 如下所示 Vienna 2012 890 503 70 London 2014 5400 879 78 London 2014 4800 70 90 Bern 2013 300 450 678 Vienna 2013 70
  • 将节点排列在特定位置

    在下面的 vis network 中 我有 2 组节点 我通过在生成一个节点后访问节点位置将 2 组节点分为左侧和右侧layout as tree 然后使用visEvents在节点组周围画了一个椭圆 以显示更定义为 2 个单元结构的分离 我
  • 如何向我的应用程序实时获取路线详细信息

    我正在为我的年终项目做一个 arduino 项目 我正在为自行车骑手制作一款智能手套 它可以通知电话 健康跟踪 地理跟踪和导航 我想知道是否有任何方法可以获取有关逐向导航到我的应用程序的详细信息 即 如果谷歌导航说 左转 则获取该详细信息并
  • 使用 Android Beam(或 S-Beam)发送大文件

    我的任务是为一个应用程序添加支持 以便通过 Android 上的 NFC 在设备之间传输大型数据文件 数十兆字节 我知道 Android 上的真正 NFC 速度非常慢 但我知道 ICS 支持将批量数据传输移交给蓝牙 三星拥有一种专有机制 可
  • java.lang.IllegalArgumentException:已添加:Lcom/google/android/gms/iid/MessengerCompat

    So I ve searched a lot on the internet already on what the error is causing me and they are all saying that a library ha
  • 在 64 位操作系统上的 32 位应用程序池中运行我的网站

    这是我的设置 开发 Windows Server 2008 64 位 视觉工作室 2008 具有 3 个类库 1 个 Web 应用程序的解决方案 暂存网络服务器 Windows Server 2008 R2 64 位 IIS7 5集成应用程
  • 如何检查输入字符串是否包含大写和小写组合?

    我想知道如何检查输入字符串是否包含大写和小写组合 之后打印一条语句以显示输入字符串包含大写和小写的组合 第0步 你需要的变量 char str int i char found lower found upper 第一步 遍历字符串 for
  • 如何使用 ASP.NET Identity 2.0 允许用户模拟另一个用户?

    我正在将 ASP NET MVC 5 1 应用程序从 MembershipProvider 迁移到 ASP NET Identity v2 0 该应用程序的功能之一是用户模拟 管理员可以像在网站上注册的任何其他用户一样登录 而无需知道密码
  • 如何在 Swing 应用程序中使用退出按钮?

    我是使用 Swing 进行 Java 表单应用程序开发的新手 用于退出应用程序的退出按钮的合适代码是什么 例如 在 C NET Framework 中我们使用Application Exit 作为退出按钮的代码 Java 中退出应用程序的等
  • 为什么对于回溯,有时我们需要在递归后显式弹出,有时则不需要?

    例如 让我们考虑一个任务 我们需要找到给定字符串的所有排列 保留字符序列但改变大小写 这是没有回溯的解决方案 pop def letterCasePermutation S type S str rtype List str def bac