代码学习记录22--回溯算法第三天

news2024/10/6 6:05:22

随想录日记part22

t i m e : time: time 2024.03.17



主要内容:今天主要是结合类型的题目加深对回溯算法的理解:1.组合总和;2.组合总和
;3.分割回文串。

  • 39. 组合总和
  • 40.组合总和II
  • 131.分割回文串


Topic1组合总和

题目:

给你一个无重复元素的整数数组 c a n d i d a t e s candidates candidates 和一个目标整数 t a r g e t target target ,找出 c a n d i d a t e s candidates candidates 中可以使数字和为目标数 t a r g e t target target 的所有不同组合 ,并以列表形式返回。你可以按任意顺序返回这些组合。
c a n d i d a t e s candidates candidates 中的同一个数字可以无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 t a r g e t target target 的不同组合数少于 150 个。

输入: c a n d i d a t e s = [ 2 , 3 , 6 , 7 ] , t a r g e t = 7 candidates = [2,3,6,7], target = 7 candidates=[2,3,6,7],target=7
输出: [ [ 2 , 2 , 3 ] , [ 7 ] ] [[2,2,3],[7]] [[2,2,3],[7]]

思路: 按照回溯模板我们进行回溯三部曲:
递归三部曲:

1.回溯函数模板返回值以及参数
在这里要定义两个全局变量, p a t h path path用来存放符合条件单一结果, r e s u l t result result用来存放符合条件结果的集合。回溯函数里一定有一个参数记录当前 p a t h path path里面值的和 n o w s u m nowsum nowsum;还需要一个参数为 i n t int int 型变量 s t a r t I n d e x startIndex startIndex
所以整体代码如下:

List<List<Integer>> result=new ArrayList<>();
LinkedList<Integer> path=new LinkedList<>();
void backtracking(int target, int start, int nowsum, int[] candidates)

2.回溯函数终止条件
回溯出口,如果 t a r g e t target target 里面的数量等于 n o w s u m nowsum nowsum,说明其到达叶子节点则将其加入到 r e s u l t result result,否则直接返回 r e t u r n return return
代码如下:

if (nowsum > target)
            return;
        if (target == nowsum) {
            result.add(new ArrayList<>(path));
            return;
        }

3.回溯搜索的遍历过程
f o r for for 循环每次从 s t a r t I n d e x startIndex startIndex 开始遍历,然后用 p a t h path path 保存取到的节点i搜索的过程如下图:
在这里插入图片描述

实现代码如下:

for (int i = start; i < candidates.length; i++) {
            path.add(candidates[i]);
            nowsum += candidates[i];
            backtracking(target, i, nowsum, candidates);// 不用i+1了,表示可以重复读取当前的数
            nowsum -= candidates[i];
            path.removeLast();
        }

完整的代码如下:

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = new LinkedList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        result.clear();
        path.clear();
        backtracking(target, 0, 0, candidates);
        return result;
    }

    private void backtracking(int target, int start, int nowsum, int[] candidates) {
        if (nowsum > target)
            return;
        if (target == nowsum) {
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = start; i < candidates.length; i++) {
            path.add(candidates[i]);
            nowsum += candidates[i];
            backtracking(target, i, nowsum, candidates);// 不用i+1了,表示可以重复读取当前的数
            nowsum -= candidates[i];
            path.removeLast();
        }
    }
}


Topic2组合总和||

题目:

给定一个候选人编号的集合 c a n d i d a t e s candidates candidates 和一个目标数 t a r g e t target target ,找出 c a n d i d a t e s candidates candidates 中所有可以使数字和为 t a r g e t target target 的组合。 c a n d i d a t e s candidates candidates 中的每个数字在每个组合中只能使用 一次 。注意:解集不能包含重复的组合。

输入: c a n d i d a t e s = [ 10 , 1 , 2 , 7 , 6 , 1 , 5 ] , t a r g e t = 8 candidates = [10,1,2,7,6,1,5], target = 8 candidates=[10,1,2,7,6,1,5],target=8
输出: [ [ 1 , 1 , 6 ] , [ 1 , 2 , 5 ] , [ 1 , 7 ] , [ 2 , 6 ] ] [ [1,1,6], [1,2,5], [1,7], [2,6] ] [[1,1,6],[1,2,5],[1,7],[2,6]]

思路: 按照回溯模板我们进行回溯三部曲:
递归三部曲:

1.回溯函数模板返回值以及参数
在这里要定义两个全局变量, p a t h path path用来存放符合条件单一结果, r e s u l t result result用来存放符合条件结果的集合。回溯函数里一定有一个参数记录当前 p a t h path path里面值的和 n o w s u m nowsum nowsum;还需要一个参数为 i n t int int 型变量 s t a r t I n d e x startIndex startIndex,还有一个用于记录是否被使用过的数组 u s e d used used
所以整体代码如下:

List<List<Integer>> result=new ArrayList<>();
LinkedList<Integer> path=new LinkedList<>();
void reback(int[] candidates,int target,int nowsum,int startindex)
boolean[] used;//记录元素是否被用过

2.回溯函数终止条件
回溯出口,如果索引值 s t a r t i n d e x startindex startindex 里面的数量等于 d i g i t s . l e n g t h ( ) digits.length() digits.length(),说明其到达叶子节点,则将 t e m p temp temp其加入到 l i s t list list,否则直接返回 r e t u r n return return
代码如下:

if(target<nowsum)return;
        if(target==nowsum){
            result.add(new ArrayList<>(path));
        }

3.回溯搜索的遍历过程
首先将原始数据进行排序,进行排序后相同的数字就会相邻。如果 c a n d i d a t e s [ i ] = = c a n d i d a t e s [ i − 1 ] 并且 u s e d [ i − 1 ] = = f a l s e candidates[i] == candidates[i - 1] 并且 used[i - 1] == false candidates[i]==candidates[i1]并且used[i1]==false,就说明:前一个树枝,使用了 c a n d i d a t e s [ i − 1 ] candidates[i - 1] candidates[i1],也就是说同一树层使用过 c a n d i d a t e s [ i − 1 ] candidates[i - 1] candidates[i1]。此时 f o r for for 循环里就应该做 c o n t i n u e continue continue 的操作。
在这里插入图片描述

实现代码如下:

for(int i=startindex;i<candidates.length;i++){
            if(i>startindex && candidates[i]==candidates[i-1])continue;
            nowsum+=candidates[i];
            path.add(candidates[i]);
            used[i]=true;
            reback(candidates,target,nowsum,i+1);
            nowsum-=candidates[i];
            path.removeLast();
            used[i]=false;
        }

完整的代码如下:

class Solution {
    List<List<Integer>> result=new ArrayList<>();//用于记录最后的结果
    List<Integer> path=new LinkedList<>();//用于记录临时结果
    boolean[] used;//记录元素是否被用过
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        result.clear();
        path.clear();
        used=new boolean[candidates.length];
        Arrays.fill(used, false);
        reback(candidates,target,0,0);
        return result;
    }
    private void reback(int[] candidates,int target,int nowsum,int startindex){
        if(target<nowsum)return;
        if(target==nowsum){
            result.add(new ArrayList<>(path));
        }
        for(int i=startindex;i<candidates.length;i++){
            if(i>startindex && candidates[i]==candidates[i-1])continue;
            nowsum+=candidates[i];
            path.add(candidates[i]);
            used[i]=true;
            reback(candidates,target,nowsum,i+1);
            nowsum-=candidates[i];
            path.removeLast();
            used[i]=false;
        }
    }
    private void reback1(int[] candidates,int target,int nowsum,int startindex){
        if(target<nowsum)return;
        if(target==nowsum){
            result.add(new ArrayList<>(path));
        }
        for(int i=startindex;i<candidates.length;i++){
            if(i>startindex && candidates[i]==candidates[i-1]){
                continue;
            }
            nowsum+=candidates[i];
            path.add(candidates[i]);
            reback(candidates,target,nowsum,i+1);
            nowsum-=candidates[i];
            path.removeLast();
        }
    }
}

时间复杂度: O ( n ∗ 2 n ) O(n * 2^n) O(n2n)
空间复杂度: O ( n ) O(n) O(n)



Topic3分割回文串

题目:

给你一个字符串 s s s,请你将 s s s 分割成一些子串,使每个子串都是回文串。返回 s s s 所有可能的分割方案。

输入: s = " a a b " s = "aab" s="aab"
输出: [ [ " a " , " a " , " b " ] , [ " a a " , " b " ] ] [["a","a","b"],["aa","b"]] [["a","a","b"],["aa","b"]]

思路:

解决该问题需要解决下面几个问题:

  • 切割问题可以抽象为组合问题
  • 如何模拟那些切割线
  • 切割问题中递归如何终止
  • 在递归循环中如何截取子串

如何判断回文按照回溯模板我们进行回溯三部曲:
递归三部曲:

1.回溯函数模板返回值以及参数
在这里要定义两个全局变量, p a t h path path用来存放符合条件单一结果, r e s u l t result result用来存放符合条件结果的集合。回溯函数里一定有一个参数记录当前 p a t h path path里面值;还需要一个参数为 i n t int int 型变量 i n d e x index index
所以整体代码如下:

List<List<String>> result = new ArrayList<>();// 存最后的结果
Deque<String> path = new LinkedList<>();// 存中间的结果
void reback(String s, int index)

2.回溯函数终止条件
回溯出口,从树形结构的图中可以看出:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止条件。
在这里插入图片描述

代码如下:

 if (index >= s.length()) {
            result.add(new ArrayList(path));
            return;
        }

3.回溯搜索的遍历过程
首先判断这个子串是不是回文,如果是回文,就加入在 p a t h path path中, p a t h path path 用来记录切割过的回文子串。

实现代码如下:

for (int i = index; i < s.length(); i++) {
            if (isHuiwen(s, index, i)) {
                String str = s.substring(index, i + 1);
                path.addLast(str);
            } else {
                continue;
            }
            reback(s, i + 1);
            path.removeLast();
        }

完整的代码如下:

class Solution {
    List<List<String>> result = new ArrayList<>();// 存最后的结果
    Deque<String> path = new LinkedList<>();// 存中间的结果

    public List<List<String>> partition(String s) {
        reback(s, 0);
        return result;
    }

    private void reback(String s, int index) {
        if (index >= s.length()) {
            result.add(new ArrayList(path));
            return;
        }
        for (int i = index; i < s.length(); i++) {
            if (isHuiwen(s, index, i)) {
                String str = s.substring(index, i + 1);
                path.addLast(str);
            } else {
                continue;
            }
            reback(s, i + 1);
            path.removeLast();
        }
        
    }
    private boolean isHuiwen(String s, int startIndex, int end) {
        for (int i = startIndex, j = end; i < j; i++, j--) {
            if (s.charAt(i) != s.charAt(j)) {
                return false;
            }
        }
        return true;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1526726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Error response from daemon Get server gave HTTP response to HTTPS client

使用docker compose拉起docker镜像时&#xff0c;若出现如下报错 Error response from daemon: Get "https://devops.test.cn:5000/v2/": http: server gave HTTP response to HTTPS client表示Docker守护进程无法从指定url获取响应&#xff0c; 可能原因有以下&…

深入理解jsp技术

目录&#xff1a; JSPJSP介绍JSP运行原理JSP标签的使用JSP原始标签的使用JSP的指令标签JSP的内置对象请求转发请求转发案例JSP中的四大作用域对象JSTL标签库EL表达式JSTL标签库与EL表达式的使用 JSP JSP介绍 JSP(全称Java Server Pages)Java服务端页面技术&#xff0c;是JavaEE…

结构体中的内存对齐是什么?一起搞懂它

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

LeetCode刷题记录:(11)组合(初识回溯算法)

leetcode传送通道 暂时记录&#xff0c;这篇没啥营养&#xff0c;不用看了 class Solution {List<List<Integer>> result new ArrayList<>(); // 存所有组合List<Integer> path new LinkedList<>(); //存每一个组合public List<List<Int…

聚信产服:引领多元化产业服务迈向新纪元

聚信产服成立于2014年&#xff0c;一家在产业服务领域拥有深厚积淀的综合性服务机构&#xff0c;专注于政府招商、园区运营、企业选址咨询及产业链服务等多元化业务。我们致力于通过高效、专业的服务&#xff0c;为政府、企业及投资者提供全方位的产业支持&#xff0c;推动区域…

【鸿蒙HarmonyOS开发笔记】动画过渡效果之布局更新动画

概述 动画的原理是在一个时间段内&#xff0c;多次改变UI外观&#xff0c;由于人眼会产生视觉暂留&#xff0c;所以最终看到的就是一个“连续”的动画。UI的一次改变称为一个动画帧&#xff0c;对应一次屏幕刷新&#xff0c;而决定动画流畅度的一个重要指标就是帧率FPS&#x…

计算机二级(Python)真题讲解每日一题:《十字叉》

描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬ ‪‬‪‬‪‬‪‬‪‬‮‬‪…

React Hooks全部总结

Hooks 概念理解 学习目标&#xff1a; 理解 Hooks 的概念及解决的问题 什么是 hooks hooks 的本质&#xff1a; 一套能够使函数组件更强大、更灵活的&#xff08;钩子&#xff09; React 体系里组件分为类组件和函数组件 多年使用发现&#xff0c;函数组件是一个更加匹配 Rea…

解决:visio导出公式为pdf图片乱码问题

今天需要将Visio编辑好的以后的图输出pdf&#xff0c;但是点击保存后公式部分一直乱码&#xff0c;如下图所示 保存为pdf后会变成&#xff1a; 解决方案&#xff1a;保存时点击文件下方的快速打印&#xff0c;存到桌面&#xff0c;不要直接点击保存

Vue3学习日记 Day1

一、简介 1、简介 Vue3是新的默认版本&#xff0c;拥有更快的速度&#xff0c;更好的语法 二、使用create-vue搭建Vue3项目 1、创建项目 1、介绍 create-vue是Vue官方新的脚手架工具&#xff0c;底层切换为了vite&#xff0c;为开发提供极速响应 2、使用 2.1、确定环境条件 2…

关于 闰年 的小知识,为什么这样判断闰年

闰年的规定&#xff1a; 知道了由来&#xff0c;我们就可以写程序来判断&#xff1a; #include <stdio.h> int main() {int year, leap;scanf("%d",&year);if((year%4 0 && year%100 ! 0) || year%400 0)leap 1;else leap 0;if(leap) printf(…

Python大数据实践:selenium爬取京东评论数据

准备工作 selenium安装 Selenium是广泛使用的模拟浏览器运行的库&#xff0c;用于Web应用程序测试。 Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样&#xff0c;并且支持大多数现代 Web 浏览器。 #终端pip安装 pip install selenium #清华镜像安装 p…

创新应用2:nnmf+DBO+K-Medoids聚类,蜣螂优化算法DBO优化K-Medoids,适合学习和发paper。

创新应用2&#xff1a;nnmfDBOK-Medoids聚类&#xff0c;蜣螂优化算法DBO优化K-Medoids&#xff0c;适合学习和发paper。 一、蜣螂优化算法 摘要&#xff1a;受蜣螂滚球、跳舞、觅食、偷窃和繁殖等行为的启发&#xff0c;提出了一种新的基于种群的优化算法(Dung Beetle Optim…

断言assert是什么?

assert是什么&#xff1f; assert断言&#xff0c;是一个被定义在<assert.h>头文件中的一个宏&#xff0c;而不是一个函数。 可以用来检查数据的合法性&#xff0c;但是频繁的调用极大影响了程序的性能&#xff0c;增加了额外的开销。可以通过#define NDEBUG来禁用asse…

计算机考研|408还是自命题?看这一篇就够了

计算机考研自命题都担心考不上&#xff0c;408估计更能让你头秃 不要光看着408的分数线低&#xff0c;自命题分数线高&#xff0c;408想拿到高分是很困难的...&#x1f630; 某双飞一本 身边大部分人都去考数据结构是因为考试内容相比于408来说少了很多&#xff0c;时间更好分配…

MySQL基础-----多表查询之子查询

目录 前言 子查询概述 1.概念 2.分类 一、标量子查询 二、列子查询 三、行子查询 四、表子查询 前言 上一期我们讲了内外连接查询以及自连接查询&#xff0c;那么本期我们就学习多表查询的子查询。本期会详细讲解什么是子查询&#xff0c;以及子查询的相关功能&#xf…

Java项目:63 ssm网上花店设计+vue

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统具备友好性且功能完善。管理员登录进入后台之后&#xff0c;主要完成花材选择管理&#xff0c;用户管理&#xff0c;鲜花管理&#xff0c;鲜花出入…

18 优先级队列

priority_queue介绍 1.优先级队列是一种容器适配器&#xff0c;根据弱排序标准&#xff0c;它的第一个元素总是最大的 2.此上下文类似于堆&#xff0c;堆中可以随时插入元素&#xff0c;检索最大堆元素 3.优先队列实现为容器适配器&#xff0c;容器适配器即将特定容器类封装作…

【源码阅读】evmⅠ

代码位置如下&#xff1a; 参考link 以太坊中有一个很重要的用途是智能合约&#xff0c;而其中evm模块是实现了执行智能合约的虚拟机。evm可以逐条解析执行智能合约的指令。 evm中的核心对象是EVM&#xff0c;代表一个以太坊虚拟机。其内部主要依赖&#xff1a;解释器Interore…

水下蓝牙耳机哪个牌子好?推荐四款高人气力作游泳耳机

在这个充满活力的时代&#xff0c;人们对于生活的追求早已不仅仅局限于日常的琐碎&#xff0c;更多的是对健康、对自我挑战的向往。运动&#xff0c;成为了现代人生活中不可或缺的一部分。而游泳&#xff0c;作为一项既能锻炼全身&#xff0c;又能享受水中美妙的运动&#xff0…