手把手教你<leetcode>中的回溯算法——多一点套路

基于ROS2 Humble与Livox Mid-360的双雷达点云融合实战解析 本文详细解析了基于ROS2 Humble与Livox Mid-360的双雷达点云融合实战方案。从环境搭建、驱动安装、双雷达配置、外参标定、时间同步到点云融合核心实现,全面介绍了技术要点与避坑指南,并提供了工程化部署与性能优化建议,助力开发者高效实现高精度点云合成应用。 阅读详情

<leetcode>是一个很强大的OJ(OnlineJudge)算法平台,其中不少题目都很经典。其中有一个系列的考察回溯算法,例如Combination Sum 系列 Subsets系列等。根据百度百科定义:回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

博主在学习回溯算法到应用其完成算法题经历了很多的困惑,查看别人博客的时候基本都是解决某个特定问题,而不是注重方法,相信不少读者看完和我一样一脸懵逼。所以博主想要尝试下写下自己总结的方法。希望这篇博客能够帮助和我一样在学习算法的人!第一次写博客,如有疏漏,欢迎指正。

首先我们来看一道题目:

Combinations:Given two integers n and k,return all possible combinations of k numbersout of 1 ... n. For example, If n = 4 and k =2, a solution is:

 

[

 [2,4],

 [3,4],

 [2,3],

 [1,2],

 [1,3],

 [1,4],

]

(做一个白话版的描述,给你两个整数 n和k,从1-n中选择k个数字的组合。比如n=4,那么从1,2,3,4中选取两个数字的组合,包括图上所述的四种。)

然后我们看看题目给出的框架:

public class Solution {

   public List<List<Integer>> combine(int n, int k) {

       

    }

}

要求返回的类型是List<List<Integer>> 也就是说将所有可能的组合list(由整数构成)放入另一个list(由list构成)中。

现在进行套路教学:要求返回List<List<Integer>>,那我就给你一个List<List<Integer>>,因此

(1)    定义一个全局List<List<Integer>> result=new ArrayList<List<Integer>>();

(2)    定义一个辅助的方法(函数)public void backtracking(int n,int k, List<Integer>list){}

n k 总是要有的吧,加上这两个参数,前面提到List<Integer> 是数字的组合,也是需要的吧,这三个是必须的,没问题吧。(可以尝试性地写参数,最后不需要的删除)

(3)    接着就是我们的重头戏了,如何实现这个算法?对于n=4,k=2,1,2,3,4中选2个数字,我们可以做如下尝试,加入先选择1,那我们只需要再选择一个数字,注意这时候k=1了(此时只需要选择1个数字啦)。当然,我们也可以先选择2,3 或者4,通俗化一点,我们可以选择(1-n)的所有数字,这个是可以用一个循环来描述?每次选择一个加入我们的链表list中,下一次只要再选择k-1个数字。那什么时候结束呢?当然是k<0的时候啦,这时候都选完了。

有了上面的分析,我们可以开始填写public void backtracking(int n,int k, List<Integer> list){}中的内容。

publicvoid backtracking(int n,int k,int start,List<Integer> list){
        if(k<0)        return;
        else if(k==0){
                       //k==0表示已经找到了k个数字的组合,这时候加入全局result中
            result.add(new ArrayList(list));
 
        }else{
            for(int i=start;i<=n;i++){
                list.add(i);//尝试性的加入i
                    //开始回溯啦,下一次要找的数字减少一个所以用k-1,i+1见后面分析
                backtracking(n,k-1,i+1,list);
                //(留白,有用=。=)
            }
        }
    }


观察一下上述代码,我们加入了一个start变量,它是i的起点。为什么要加入它呢?比如我们第一次加入了1,下一次搜索的时候还能再搜索1了么?肯定不可以啊!我们必须从他的下一个数字开始,也就是2 、3或者4啦。所以start就是一个开始标记这个很重要啦!

这时候我们在主方法中加入backtracking(n,k,1,list);调试后发现答案不对啊!为什么我的答案比他长那么多?


回溯回溯当然要退回再走啦,你不退回,当然又臭又长了!所以我们要在刚才代码注释留白处加上退回语句。仔细分析刚才的过程,我们每次找到了1,2这一对答案以后,下一次希望2退出然后让3进来,1 3就是我们要找的下一个组合。如果不回退,找到了2 ,3又进来,找到了3,4又进来,所以就出现了我们的错误答案。正确的做法就是加上:list.remove(list.size()-1);他的作用就是每次清除一个空位 让后续元素加入。寻找成功,最后一个元素要退位,寻找不到,方法不可行,那么我们回退,也要移除最后一个元素。

所以完整的程序如下:

public class Solution {
   List<List<Integer>> result=new ArrayList<List<Integer>>();
   public List<List<Integer>> combine(int n, int k) {
       List<Integer> list=new ArrayList<Integer>();
       backtracking(n,k,1,list);
       return result;
    }
   public void backtracking(int n,int k,int start,List<Integer>list){
       if(k<0) return ;
       else if(k==0){
           result.add(new ArrayList(list));
       }else{
           for(int i=start;i<=n;i++){
                list.add(i);
                backtracking(n,k-1,i+1,list);
                list.remove(list.size()-1);
            }
       }
    }
}


是不是有点想法了?那么我们操刀一下。

Combination Sum

Given a set ofcandidate numbers (C) and a target number (T), findall unique combinations in C where thecandidate numbers sums toT.

The same repeated numbermay be chosen from C unlimited numberof times.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

For example,given candidate set [2, 3, 6, 7] and target 7, 
A solution set is:
 

[

 [7],

  [2,2, 3]

]

(容我啰嗦地白话下,给你一个正数数组candidate[],一个目标值target,寻找里面所有的不重复组合,让其和等于target,给你[2,3,6,7] 2+2+3=7 ,7=7,所以可能组合为[2,2,3],[7])

按照前述的套路走一遍:

public class Solution {

   List<List<Integer>> result=new ArrayList<List<Integer>>();

   public List<List<Integer>> combinationSum(int[] candidates,int target) {

       Arrays.sort(candidates);

       List<Integer> list=new ArrayList<Integer>();

       return result;

    }

   public void backtracking(int[] candidates,int target,int start,){       

    }

}

(1)      全局List<List<Integer>> result先定义

(2)      回溯backtracking方法要定义,数组candidates 目标target 开头start 辅助链表List<Integer> list都加上。

(3)      分析算法:以[2,3,6,7]  每次尝试加入数组任何一个值,用循环来描述,表示依次选定一个值

for(inti=start;i<candidates.length;i++){

                    list.add(candidates[i]);

                }

接下来回溯方法再调用。比如第一次选了2,下次还能再选2是吧,所以每次start都可以从当前i开始(ps:如果不允许重复,从i+1开始)。第一次选择2,下一次要凑的数就不是7了,而是7-2,也就是5,一般化就是remain=target-candidates[i]所以回溯方法为:

backtracking(candidates,target-candidates[i],i,list);

然后加上退回语句:list.remove(list.size()-1);

那么什么时候找到的解符合要求呢?自然是remain(注意区分初始的target)=0了,表示之前的组合恰好能凑出target。如果remain<0 表示凑的数太大了,组合不可行,要回退。当remain>0 说明凑的还不够,继续凑。

所以完整方法如下:

publicclass Solution {
    List<List<Integer>> result=newArrayList<List<Integer>>();
    public List<List<Integer>>combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);//所给数组可能无序,排序保证解按照非递减组合
        List<Integer> list=newArrayList<Integer>();
        backtracking(candidates,target,0,list);//给定target,start=0表示从数组第一个开始
        return result;//返回解的组合链表
    }
    public void backtracking(int[]candidates,int target,int start,List<Integer> list){
       
            if(target<0)    return;//凑过头了
            else if(target==0){
               
                result.add(newArrayList<>(list));//正好凑出答案,开心地加入解的链表
               
            }else{
                for(inti=start;i<candidates.length;i++){//循环试探每个数
                    list.add(candidates[i]);//尝试加入
		   //下一次凑target-candidates[i],允许重复,还是从i开始
                   backtracking(candidates,target-candidates[i],i,list);                   
		   list.remove(list.size()-1);//回退
                }
            }
       
    }
}

是不是觉得还是有迹可循的?下一篇博客将部分回溯算法拿出来,供大家更好地发现其中的套路。

链接如下:

回溯法欣赏



【测试】echo发送和接收TCP/UDP数据包|shell 发送TCP/UDP数据包 目录 通过/dev/tcp、/dev/udp shell给tcp或udp服务发送16进制报文指令 通过/dev/tcp、/dev/udp (https://blog.youkuaiyun.com/u010039418/article/details/86251470) 通过/dev/tcp、/dev/udp可以直接在shell脚本中发起tcp、udp连接,方便又高效,平时用于测试啥的还是挺方便的。 直接发送 格式 /dev/udp/ip/port 比如要向本地10001端口发送数据,可以使用 ec. 阅读详情

相关推荐

Kafka延迟队列实现方案全解析

$ \text{时间轮} = \text{环形数组} + \text{分层设计} $$需要补充代码实例或特定场景的优化方案可进一步细化,此大纲已覆盖核心技术路径。

lz989796的博客 818

搜索算法——回溯总结01

回溯算法,常常用于解决连暴力都解不了的一些难题

keepstrivingchy的博客 3443

ROS激光雷达动态避障算法优化(C++实战)

本文深入探讨了ROS激光雷达动态避障算法的C++实战优化。针对动态环境的核心挑战,文章系统性地介绍了从激光数据预处理(降噪、瘦身)、动态障碍物检测与跟踪,到基于动态窗口法(DWA)的智能决策与调优的全流程。重点分享了如何将障碍物速度预测融入DWA打分函数,以实现更安全、流畅的避障,并提供了工程架构、性能优化及真机调试的实用建议。

weixin_29192141的博客 947

【回溯专题】—— 回溯算法入门篇

当前包含全排列、N皇后、组合、电话号码的字符组合

欢迎来到我的世界 3874

西门子博图指令(定时器操作三)

西门子博图定时器中复位定时器功能指令介绍

yue008的博客 8873

【技能】OpenClaw Memory 与 MemOS 两种 AI 记忆方案深度解析

摘要:本文对比了两种AI记忆系统方案。OpenClaw Memory是轻量级记忆助手,内置SQLite存储,支持语义搜索,部署简单成本低,适合日常对话记忆需求。MemOS是自学习系统,通过Neo4j和Qdrant实现技能自进化,但需部署4套服务,门槛高成本大。建议普通用户选择OpenClaw Memory,技术玩家可逐步尝试MemOS。两种方案各具优势,需根据实际需求选择。

海兰 199

回溯算法及其应用

回溯算法是一种常用于解决组合优化问题、搜索问题和决策问题的算法。事实上,回溯正是的副产物,回溯算法就是通过递归实现的算法。他通过遍历所有情况来找到问题的解,若当前方案不可行,就会回溯(回退)并尝试其他可能的路径。和多层嵌套for循环相比,这种递归试错的方法不必设计的for循环,有效减轻了代码的复杂度,有利于算法在大规模的搜索空间中寻找最佳解决方案。回溯算法的本质是所有可能情况,虽然它的时间复杂度可能很高,但在许多复杂情况下,它仍然是一个可行的解决方案。

m0_72379992的博客 1965

大数据分析实验,包含五个子实验:wordCount实验,PageRank实验,关系挖掘实验,k-means算法,推荐系统算法。

大数据分析实验,包含五个子实验:wordCount实验,PageRank实验,关系挖掘实验,k-means算法,推荐系统算法。

805

算法:什么是回溯

回溯是递归的一种形式。 通常情况下,你会面临很多选择,你必须从中选择一个。在你做出选择后,你会得到一组新的选项;你得到的选择取决于你做出的选择。这个过程反复进行,直到达到最终状态。如果你做出了一系列正确的选择,你的最终状态就是目标状态;如果你没有,那就不是正确答案了 从概念上讲,你从树根开始,这棵树可能有一些叶子,这些叶子有可能是好的,又有可能是坏的。你要找到一片好叶子。 在每个节点上,从根节点开始,选择它的一个子节点进行移动,并一直这样做,直到到达叶节点。 假设你碰到一片坏叶子,通过撤销最近的选择,并尝

OceanStar的博客 5462

单板电源设计(LDO、DC/DC)

高速电路设计的电源架构 在电路设计中,一块单板往往涉及多种电源,常见的如5V/3.3V/2.5V/1.8V/1.5V/1.2V/1V0.9V/0.75V等,如此多种类的电源不可能都直接通过背板从电源板获得。一般,单板仅有一种或者两种输入电源,如48V或12V,再由它们产生单板上器件所需要的电源。 单板如何由输入电源生成所需电源,常见有两种架构:集中式电源架构和分布式电源架构。 ...

sinat_15677011的博客 8333

FAST-LIO论文公式解析

FAST-LIO论文公式解析

努力努力努力 670

回溯算法详解

算法思想 回溯实际上是一种试探算法,这种算法跟暴力搜索最大的不同在于,在回溯算法里,是一步一步地小心翼翼地进行向前试探,会对每一步探测到的情况进行评估,如果当前的情况已经无法满足要求,那么就没有必要继续进行下去,也就是说,它可以帮助我们避免走很多的弯路。 回溯算法的特点在于,当出现非法的情况时,算法可以回退到之前的情景,可以是返回一步,有时候甚至可以返回多步,然后再去尝试别的路径和办法。这也就意味着,想要采用回溯算法,就必须保证,每次都有多种尝试的可能。 解题步骤 判断当前情况是否非法,如果非法就立即返

杂文集 2万+

mjlab MuJoCo 人形机器人强化学习入门教程(一)安装配置使用

mjlab是融合IsaacLab API与MuJoCo物理引擎的强化学习工具,提供轻量级GPU加速仿真方案。当前处于测试阶段,支持Linux系统(推荐)和有限macOS支持。核心优势包括:1)直接集成MuJoCo Warp实现裸机性能;2)保留IsaacLab成熟的RL抽象层;3)简化安装流程。与IsaacLab相比更专注于MuJoCo生态,适合刚体机器人RL研究。文档包含详细安装指南、平台兼容性说明、与IsaacLab的API差异对比及常见问题解答。项目正在积极开发中,欢迎社区贡献和反馈。

2506_90492529的博客 2002

【算法分析与设计】回溯法(上)

计算机算法分析与设计中有关回溯法的讲解,主要包括学习要点、回溯法的基本思想、回溯算法的适用条件、递归回溯、迭代回溯、子集树与排列树、装载问题、批处理作业调度问题

東方緋想天 1175

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

回溯算法总结篇

定义 首先先来了解一下回溯的定义吧 回溯是递归的副产物,只要有递归就会有回溯 所以回溯经常和二叉树,深度优先遍历等操作联系到一起,因为他们都用到了递归。 回溯本质上是暴力搜索,效率并不高,最多剪枝一下。 回溯法可以解决的问题 组合问题:N个数里面按一定规则找出k个数的集合 排列问题:N个数按一定规则全排列,有几种排列方式 切割问题:一个字符串按一定规则有几种切割方式 子集问题:一个N个数的集合里有多少符合条件的子集 棋盘问题:N皇后,解数独等等 回溯模板(重点) void backtracking(

passport404的博客 1006

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

算法-- 回溯算法 及 示例

回溯法介绍 回溯法(英语:backtracking)也称试探法,回溯法有“通用的解题方法”之称。它可以系统的搜索一个问题的所有解或者任意解。 回溯法是一个既带有系统性又带有跳跃性的的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点 出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过 对以该结点为根的子

Daniel 的技术笔记 不积跬步无以至千里,不积小流无以成江海。 9437

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

回溯

     回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。用回溯算法解决问题的一般步骤为: 一、定义一个解空间,它包含问题的解。 二、利用适于搜索的方法组织解空间。 三、利用深度优先法搜索解空间。 四、利用限界函数避免移动到不可能产生解的子空间。  回溯-解释    问题的解空间通常是在

乐吾天 1007

循序渐进,搞懂什么是回溯算法

搞懂回溯算法。

weixin_43790276的博客 3446

常用算法之一——回溯

1 回溯法 回溯法的基本做法就是搜索,或者是一种组织的井井有条的,能够避免不必要搜索的穷举式搜索。这种方法适合与解一些组合数相当大的问题。 回溯法在问题的解空间树中,按照深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该节点是否包含问题的解。如果肯定不包含,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索,即走不通就掉...

pengbinyt的博客 733

回溯算法精讲

其实组合问题,最经典就是77题的组合,其他题型无非就是在此基础上加入了路径的值,或者不能重复。怎么去重?去什么的重?树枝上?还是同一树层?怎么使用visited,来判断是否经历过这个节点?// used[i - 1] == true,说明同一树枝candidates[i - 1]使用过// used[i - 1] == false,说明同一树层candidates[i - 1]使用过组合问题最基础还是77题,基本都是在此基础上的衍生。return;i<=n;i++)// 不能重复选择。

qq_51065805的博客 1118

【算法基础】回溯(Backtracking)

回溯是递归的一种形式,同时也是递归的副产品,也就是说只要有递归就会有回溯。在遇到必须从多种选项中选择一项的时候,你选择了一项后又会出现多种选项供选择,直到选择到了“正确的选项”函数才结束。因此,回溯法解决的问题都可以抽象为树形结构(不一定是二叉树)。回溯虽然是一种非常典型的递归算法,但是任何递归算法都可以重写为堆栈算法。事实上,这就是递归算法被翻译成机器或汇编语言的方式。

2301_78942293的博客 1669

C++算法八股——回溯(含代码)

C++算法八股——回溯(含代码)

m0_63084056的博客 175

回溯算法及题目

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1: 输入:n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]

weixin_57023347的博客 2150

LeetCode算法之----回溯

回溯算法

程序大视界 1405

Leetcode学习之回溯算法

1. 回溯算法理论基础 什么是回溯法 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。 在二叉树系列中,我们已经不止一次,提到了回溯,例如二叉树:以为使用了递归,其实还隐藏着回溯。 回溯是递归的副产品,只要有递归就会有回溯。 所以回溯函数也就是递归函数,指的都是一个函数。 回溯法的效率 回溯法的性能如何呢,必须强调的是,虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法。 **因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,**如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回

frighting_ing的博客 5361
下一篇: leetcode回溯法欣赏——配合前文套路教学效果更佳
versencoder
博客等级 码龄10年 30粉丝 15原创
评论 21
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值