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

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(使用前将#替换为@)

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

  • 用于整数分区的优雅 Python 代码 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我尝试编写代码来解决标准整数分区问题 维基百科 http en wikipedia org wiki Partition 28numb
  • 地图应用的聚类算法

    我正在研究地图上的聚类点 纬度 经度 对于快速且可扩展的合适算法有什么建议吗 更具体地说 我有一系列纬度 经度坐标和一个地图视口 我正在尝试将靠近的点聚集在一起以消除混乱 我已经有了解决问题的方法 see here http bouldr
  • StackOverflowError 计算 BigInteger 的阶乘?

    我正在尝试编写一个Java程序来计算大数的阶乘 它似乎BigInteger无法容纳这么大的数量 下面是我编写的 简单的 代码 public static BigInteger getFactorial BigInteger num if n
  • 对矩阵进行舍入,保留行和列总计

    想要 以保留行和列总计的方式对矩阵进行舍入的 伪 代码 问题从向量开始 X and Y of 非负整数 with Sum X Sum Y 想要圆X Y Sum X 同时保留行和列总计 这是婚姻问题的一种 Xa需要进行一定次数的握手 拨打该号
  • Python 中的空填字游戏求解器

    我得到了一个包含填字游戏蓝图的矩阵 当然 它是空的 我们的目标是填补整个难题 这是 Checkio 的一项任务 我已经为此奋斗了相当长一段时间 根据我对复杂性的理解 这个问题没有完美的算法 不过 必须有最好的方法来做到这一点 对吧 我尝试了
  • 计算具有 3 个循环的算法的复杂度

    我尝试解决以下练习 以下代码片段最坏情况运行时间的增长顺序是什么 作为 N 的函数 int sum 0 for int i 1 i lt N i for int j 1 j lt i i j for int k 1 k lt j j k s
  • 如何设计一种算法来计算倒数式数学数字难题

    我一直想这样做 但每次我开始思考这个问题时 它的指数性质都会让我大吃一惊 我希望能够理解的问题解决器和代码是针对倒计时数学问题的 给定一组数字 X1 到 X5 计算如何使用数学运算将它们组合起来生成 Y 您可以应用乘法 除法 加法和减法 那
  • 填充体积算法

    我有一个具有一定尺寸长度 宽度 高度的盒子 我有不同长度 宽度 高度的物品 是否有现有的算法可以确定放入盒子中的最佳物品 这称为装箱 切割库存 背包问题 并且是 NP 难问题 一般来说 您只能通过使用启发式方法获得近似解 请参见示例 htt
  • 在 3d 网格中转发(绘制)线

    我需要类似 Bresenham 算法的东西 但是 对于 3d 网格空间来说不完全是这样 我需要 3d 单元网格 边缘尺寸 1 0 从 S 点开始 前进到 K 点 接触 该线接触的所有单元格 即使只有边缘 点被触摸我需要触摸所有 8 个单元
  • 一种良好且简单的随机性测量方法

    获取一长整数序列 例如 100 000 个 并返回序列随机性的测量值的最佳算法是什么 该函数应返回单个结果 如果序列并非完全随机 则返回 0 如果完全随机 则返回 1 如果序列有点随机 它可以给出介于两者之间的东西 例如0 95 可能是一个
  • 关于Marching Cubes算法的澄清

    关于Marching Cubes 我对其算法和实现有一些疑问 我已经阅读了 Marching Cubes 的 Paul Bourke 优秀文章以及网站上可用的源代码 但是 我在理解以及如何以自己的方式实现算法方面仍然遇到了一些问题 问题如下
  • 检查有效的 IMEI

    有人知道如何检查有效的 IMEI 吗 我找到了一个可以检查此页面的功能 http www dotnetfunda com articles article597 imeivalidator in vbnet aspx http www do
  • 数独算法,暴力破解[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在尝试
  • 什么是“朴素”算法,什么是“封闭式”解决方案?

    我有一些关于描述算法时使用的术语语义的问题 首先 朴素 算法是什么意思 这与给定问题的其他解决方案有何不同 解决方案还可以采取哪些其他形式 其次 我听到很多人提到 封闭式 解决方案 我也不知道这意味着什么 但在尝试解决递归关系时经常会出现
  • 如何在 C# 中以编程方式创建柔和的颜色?

    根据所需的颜色数量均匀分布地生成它们 如果指定的计数为 8 则看起来像这样 List
  • 为什么这个算法的Big-O复杂度是O(n^2)?

    我知道这个算法的大O复杂度是O n 2 但我不明白为什么 int sum 0 int i 1 j n n while i lt j sum 即使我们设定了j n n一开始 我们在每次迭代期间递增 i 并递减 j 因此最终的迭代次数不应该比n
  • 总和不小于 key 的数组的最小子集

    给定一个数组 假设为非负整数 我们需要找到最小长度子集 使得元素之和不小于 K K 是作为输入提供的另一个整数 是否有可能找到时间复杂度为 O n n 的大 oh 的解决方案 我目前的想法是这样的 我们可以在 O n log n 中对数组进
  • 如何计算 3D Morton 数(交织 3 个整数的位)

    我正在寻找一种快速计算 3D Morton 数的方法 这个网站 http www graphics stanford edu seander bithacks html InterleaveBMN有一个基于幻数的技巧来处理 2D Morto
  • 颜色逻辑算法

    我们正在构建一个体育应用程序 并希望将团队颜色融入到应用程序的各个部分 现在 每个团队都可以使用几种不同的颜色来表示 我想做的是执行检查以验证两个团队颜色是否在彼此一定的范围内 这样我就不会显示两个相似的颜色 因此 如果团队 1 的主要团队
  • 在一个区域中拟合二维多边形的算法?

    这有标准吗 算法名称 说 我有 10 个不同大小的多边形 我有一个特定大小的区域 我想知道如何填充该区域中的最多多边形 以及它们是如何拟合的 笔记 多边形可以根据限制集进行旋转 一个可能的名称是包装问题 http en wikipedia

随机推荐

  • 维基百科 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