算法系列--递归,回溯,剪枝的综合应用(1)

💕"对相爱的人来说,对方的心意,才是最好的房子。"💕
作者:Lvzi
文章主要内容:算法系列–递归,回溯,剪枝的综合应用(1)
在这里插入图片描述

大家好,今天为大家带来的是算法系列--递归,回溯,剪枝的综合应用(1)

1.全排列(重点)

链接:
https://leetcode.cn/problems/permutations/description/
在这里插入图片描述

分析:

1.画出决策树

所谓的决策树就是我们小时候学排列画的树状图,通过一个树枚举出所有的情况
在这里插入图片描述
画出决策树之后,分析每一层干的事情是否相同(一般都是相同的),对于本题,每一层干的事可以总结为

  • 枚举出所有符合条件的排列情况

注意:决策树画的越详细越好(包括所有不符合条件的情况也画出来),有助于我们后面设计代码

2.设计代码

设计代码主要从两个方面考虑

  1. 全局变量
  2. dfs函数

1.全局变量

模拟决策的过程,想想需要哪些变量,首先题目要求的返回值是一个二维数组,所以需要设计一个ret作为返回值,当我们在枚举出所有的情况时,要考虑到枚举的数字是否被使用,如果被使用就不能被枚举,所以要标记搜索路径上数字的使用情况,所以要创建一个布尔类型的数组,接着当我们走到叶子结点时,需要保存当前排列的情况,一共就三个数字,所以需要使用一个数组进行保存,接着当从叶子结点向上返回时,我们需要舍弃掉数组中最后一个数字,这个操作比较简单,可以直接对数组进行变动即可

  • List<List> ret: 最后的返回值,用于记录所有排列情况
  • List path: 用于记录每一次dfs的结果
  • boolean[] check : 用于标记搜索过程中数字的使用情况

2.dfs函数

和递归相同,dfs函数的设计我们只需要关注某一个子问题的具体操作即可

把数组中所有的数都枚举一遍,只要没有用过,就添加到path后面

3.细节问题

  • 剪枝:在check中被标记为true,就进行剪枝

  • 回溯:如图
    在这里插入图片描述

  • 递归出口:当path中元素的数目和nums中元素的数目相同时,递归结束,将path中的所有元素添加到ret之中

4.代码实现

class Solution {
    // 全局变量
    List<List<Integer>> ret;// 返回值
    List<Integer> path;// 记录搜索路径
    boolean[] check;// 标记是否被使用过

    public List<List<Integer>> permute(int[] nums) {
        ret = new ArrayList<>();
        path = new ArrayList<>();
        check = new boolean[nums.length];

        dfs(nums);
        return ret;
    }

    public void dfs(int[] nums) {
        // 递归出口
        if(nums.length == path.size()) {
            ret.add(new ArrayList<>(path));
            return;
        }

        // 函数体
        for(int i = 0; i < nums.length; i++) {
            if(check[i] == false) {
                path.add(nums[i]);
                check[i] = true;
                dfs(nums);

                // 回溯
                check[i] = false;
                path.remove(path.size() - 1);
            }
        }
    }
}

为什么不是ret.add(path);

在这里插入图片描述

2.⼦集

链接:
https://leetcode.cn/problems/subsets/description/

分析:
画决策树:

根据定义选或者不选当前数
在这里插入图片描述

每一层都在干啥
分别枚举出选当前数字选和不选当前数的所有情况

设计代码:

全局变量:模拟整个过程,需要两个变量

  • ret:接收每次搜索的结果,是最终的返回值
  • path: 表示搜索路径的结果

dfs: 需要一个数组和当前的位置(下标),因为我需要知道当前的数是谁

细节问题:

  • 剪枝:不需要
  • 回溯:只有当选择选当前数的情况时,在返回的时候需要删除这个数
  • 递归出口:当pos走到n.length时表示数组遍历完毕,结束递归,将path添加进ret之中

代码:

class Solution {
    // 全局变量
    List<List<Integer>> ret;
    List<Integer> path;

    public List<List<Integer>> subsets(int[] nums) {
        ret = new ArrayList<>();
        path = new ArrayList<>();
        dfs(nums,0);
        return ret;
    }

    public void dfs(int[] nums,int pos) {
        // 递归出口
        if(pos == nums.length) {
            ret.add(new ArrayList<>(path));
            return;
        }

        // 选
        path.add(nums[pos]);
        dfs(nums,pos + 1);
        path.remove(path.size() - 1);// 回溯

        // 不选
        dfs(nums,pos + 1);
    }
}

这种决策树的遍历类似于二叉树遍历中的后序遍历

第二种决策树

在这里插入图片描述

以当前位置的值为起始位置,枚举出后面所有的数字的情况

class Solution {
    // 全局变量
    List<List<Integer>> ret;
    List<Integer> path;

    public List<List<Integer>> subsets(int[] nums) {
        ret = new ArrayList<>();
        path = new ArrayList<>();
        dfs(nums,0);
        return ret;
    }

    public void dfs(int[] nums,int pos) {
        // 这个遍历类似于前序遍历  根左右
        ret.add(new ArrayList<>(path));// 刚进来的时候path为空 空集也是子集的一种

        // 从当前位置一直遍历到结束
        for(int i = pos; i < nums.length; i++) {
            path.add(nums[i]);
            dfs(nums,i+1);

            path.remove(path.size() - 1);// 回溯
        }
    }
}

这种遍历的方式类似于二叉树遍历中的前序遍历,先打印根节点的值,再去遍历左右子树

总结:

  1. 画出具体详细的决策树,模拟每一步都是在干啥,明确操作
  2. 设计代码,具体来说是要设计出需要的全局变量和dfs,设计dfs和我们之前递归过程中设计函数头,函数体,递归出口一样,这不过这里的逻辑会更加的复杂一点
  3. 注意细节问题:主要从两个方面考虑
    • 剪枝
    • 回溯

3.找出所有⼦集的异或总和再求和

链接:
https://leetcode.cn/problems/sum-of-all-subset-xor-totals/

分析:
在这里插入图片描述

代码:

class Solution {
    // 全局变量
    int ret;
    int path;
    public int subsetXORSum(int[] nums) {
        dfs(nums,0);
        return ret;
    }

    public void dfs(int[] nums,int pos) {
        ret += path;

        for(int i = pos; i < nums.length; i++) {
            path ^= nums[i];
            dfs(nums,i + 1);// 递归下一个位置

            path ^= nums[i];// 回溯
        }
    }
}

注意这里面利用了^运算的性质,a ^ a = 0

还是那句话,画出决策树一切都好办!!!

四.全排列II

链接:
https://leetcode.cn/problems/permutations-ii/

分析:

相较于全排列I多了个限制条件不能有重复的组合出现,那么只需分析出所有的不合法的情况即可
1.

  1. 同一层中(同一位置比如选择第一个位置的数),不能选择重复的数字
  2. 和全排列I一样,不能选择已经使用过的数字

对于2的处理和全排列I的处理方式相同,使用一个布尔类型的check数组标记即可,对于1需要判断出 不合法的数据,首先要和前面的数字相同nums[i] == nums[i - 1],i不能越界i != 0,其次上述两个条件还不能完全判定出是不合法的数据,还必须要保证前一个数字是同一层的,check[i - 1] == false

总结来说就是:

  1. nums[i] == nums[i-1] && 在同一层–>不合法数据–>不能dfs
  2. nums[i] == nums[i-1] && 不在同一层–>合法数据–>能dfs

此外,为了保证相同的数据是紧挨着的,还需要进行排序

代码:

class Solution {
    // 全局变量
    List<List<Integer>> ret;// 返回值
    List<Integer> path;// 记录搜索路径
    boolean[] check;// 标记是否被使用过
    public List<List<Integer>> permuteUnique(int[] nums) {
        ret = new ArrayList<>();
        path = new ArrayList<>();
        check = new boolean[nums.length];
        Arrays.sort(nums);

        dfs(nums);
        return ret;

    }

    public void dfs(int[] nums) {
        // 递归出口
        if(path.size() == nums.length) {
            ret.add(new ArrayList<>(path));
            return;
        }

        // 函数体
        for(int i = 0; i < nums.length; i++) {
            // 剪枝  不合法的数据
            if(check[i] == true || (i != 0 && nums[i] == nums[i - 1] && check[i - 1] == false)) {
                continue;
            }
            path.add(nums[i]);
            check[i] = true;
            dfs(nums);

            // 回溯
            check[i] = false;
            path.remove(path.size() - 1);
        }
    }
}

5.电话号码的字⺟组合

链接:
https://leetcode.cn/problems/letter-combinations-of-a-phone-number/
分析:

每一层所做的事情:

  • 枚举出当前数字对应的字符串中所有的字符

设计代码:
1.全局变量
ret:返回值
path
string[] map:映射关系

2.dfs(digits,pos)
pos表示digits中字符的下标
递归出口:
走到最后一个节点的位置

回溯:
删除最后添加的数字

剪枝:无

在这里插入图片描述
代码:

class Solution {
    List<String> ret;// 返回值
    StringBuffer path;// 记录搜索路径
    String[] map= {"","","abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};// 建立映射关系

    public List<String> letterCombinations(String digits) {
        ret = new ArrayList<>();
        path = new StringBuffer();
        if(digits.length() == 0) return ret;// 处理为空的情况

        dfs(digits,0);
        return ret;
    }

    private void dfs(String digits, int pos) {
        if(pos == digits.length()) {// 递归出口
            ret.add(path.toString());
            return;
        }

        String s = map[digits.charAt(pos) - '0'];// 获取当前层的字符串
        for(int i = 0; i < s.length(); i++) {
            path.append(s.charAt(i));// 追加字符
            dfs(digits, pos + 1);
            path.deleteCharAt(path.length() - 1);// 回溯
        }
    }
}

dfs是往下,是递归,每一层是要做的事情是子问题

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Multisim14.2仿真参数的修改

本内容讲述Multisim14.2仿真参数的修改&#xff0c;以放大倍数修改为例说明。紫色文字是超链接&#xff0c;点击自动跳转至相关博文。持续更新&#xff0c;原创不易&#xff01; 目录&#xff1a; 1、三极管放大倍数的修改 2、Uc的电压计算 1、三极管放大倍数的修改 在仿真…

2024第16届成都实验室装备展6月1日举办

2024第16届成都实验室装备展6月1日举办 邀请函 主办单位&#xff1a; 中国西部教体融合博览会组委会 承办单位&#xff1a;重庆港华展览有限公司 博览会主题&#xff1a;责任教育 科教兴邦 展会背景 现代高新技术与基础科学实验研究对科学仪器的先进性、稳定性、性价比等…

【BlossomRPC】接入注册中心

文章目录 NacosZookeeper自研配置中心 RPC项目 配置中心项目 网关项目 这是BlossomRPC项目的最后一篇文章了&#xff0c;接入完毕注册中心&#xff0c;一个完整的RPC框架就设计完成了。 对于项目对注册中心的整合&#xff0c;其实我们只需要再服务启动的时候将ip/port/servic…

2024阿里云服务器ECS u1实例性能测评_CPU内存_网络_存储

阿里云服务器u1是通用算力型云服务器&#xff0c;CPU采用2.5 GHz主频的Intel(R) Xeon(R) Platinum处理器&#xff0c;ECS通用算力型u1云服务器不适用于游戏和高频交易等需要极致性能的应用场景及对业务性能一致性有强诉求的应用场景(比如业务HA场景主备机需要性能一致)&#xf…

Php_Code_challenge13

题目&#xff1a; 答案&#xff1a; 解析&#xff1a; 开启一个会话&#xff0c;在SESSION变量"nums"为空时则对"nums","time","whoami"进行赋值&#xff0c;并在120秒后关闭会话&#xff0c;创建一个变量"$value"…

2024051期传足14场胜负前瞻

2024051期售止时间为4月2日&#xff08;周一&#xff09;22点00分&#xff0c;敬请留意&#xff1a; 本期深盘多&#xff0c;1.5以下赔率2场&#xff0c;1.5-2.0赔率2场&#xff0c;其他场次是平半盘、平盘。本期14场难度中等偏上。以下为基础盘前瞻&#xff0c;大家可根据自身…

Hamcrest断言框架

一、Hamcrest简介 Hamcrest源于Java&#xff0c;支持多种语言&#xff0c;是用于编写匹配器对象的框架&#xff0c;可以更灵活的定义“匹配”规则。Hamcrest 断言&#xff0c;基于更灵活的 Matchers 断言方式。 二、Hamcrest安装 可以使用常用的python打包工具来安装Hamcres…

电商技术揭秘二:电商平台推荐系统的实现与优化

文章目录 一、推荐系统的重要性1.1 提升用户体验1.1.1 个性化推荐增强用户满意度1.1.2 减少用户选择困难 1.2 增加销售额1.2.1 促进交叉销售和捆绑销售1.2.2 提高用户购买转化率 1.3 数据分析与用户行为理解1.3.1 挖掘用户偏好和购买习惯1.3.2 为产品开发和库存管理提供数据支持…

思考: 什么时候需要disable MMU/i-cache/d-cache?

快速链接: 【精选】ARMv8/ARMv9架构入门到精通-[目录] &#x1f448;&#x1f448;&#x1f448; 在armv8/armv9的aarch64架构下&#xff0c;软件的启动流程&#xff1a; BL1--->BL2--->BL31--->BL32--->BL33.... 在不同的BL镜像切换时&#xff0c;都需要disable …

943: 顺序表插入操作的实现

学习版 【C语言】 需要扩充数组 【C】 #include <iostream> #include <vector> #include <algorithm> using namespace std; class MyLinkedList { public:struct LinkedNode{int val;LinkedNode* next;LinkedNode(int x) :val(x), next(NULL) {}};MyLin…

切换ip地址的app,简单易用,保护隐私

在数字化时代&#xff0c;IP地址作为网络设备的标识&#xff0c;不仅承载着数据在网络间的传输任务&#xff0c;还在一定程度上关联着用户的隐私和安全。因此&#xff0c;切换IP地址的App应运而生&#xff0c;为用户提供了一种便捷的方式来改变其网络身份&#xff0c;实现匿名浏…

制造业需要有品牌力和生命力的产品,CRM能做什么?

以往谈及制造业的数字化转型&#xff0c;生产制造环节往往是重点。但从中国制造走向中国创造&#xff0c;需要有生命力和品牌力的产品。全面推进制造业高质量发展&#xff0c;须重视客户与营销环节的变革&#xff0c;将客户与产品有效连通&#xff0c;实现价值升级。 大连冶金…

汉语语音基本特性

发音的生理基础和过程 人的发音生理机构如图 2.3.1所示,发音时由肺部收缩送出一股直流空气,经气管流至喉头声门处(声门即声带开口处),在发声之初,声门处的声带肌肉收缩,声带并拢间隙小于 1mm,这股直流空气冲过很小的缝隙,使声带得到横向和纵向的速度,此时,声带向两边运动,缝隙…

LeetCode-热题100:48. 旋转图像

题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a; matrix [[1,2,3],[4,5,6],…

1236. 递增三元组:做题笔记

目录 暴力 代码 二分 代码 前缀和 代码 推荐视频讲解 暴力 这道题说的是有三个元素数量相同的数组&#xff0c;想知道有多少个三元组满足&#xff1a;三个数分别来自 A B C数组且呈现递增。 我想的是既然要求递增&#xff0c;那就先把数组数据都排一下序&#xff0c;…

行车记录打不开?别慌,数据恢复有高招!

行车记录打不开&#xff0c;这恐怕是许多车主都曾经遭遇过的烦恼。在驾驶途中&#xff0c;行车记录仪本应是记录美好瞬间、保障行车安全的重要工具&#xff0c;但一旦它出现打不开的情况&#xff0c;所有的期待与信赖便瞬间化为乌有。面对这种情况&#xff0c;我们该如何应对&a…

HQL,SQL刷题,尚硅谷(初级)

目录 相关表数据&#xff1a; 题目及思路解析&#xff1a; 多表连接 1、课程编号为"01"且课程分数小于60&#xff0c;按分数降序排列的学生信息 2、查询所有课程成绩在70分以上 的学生的姓名、课程名称和分数&#xff0c;按分数升序排列 3、查询该学生不同课程的成绩…

python_绘图_多条折线图绘制_显示与隐藏

1. 需求 给定一个二维数组 100行, 5列, 每一列绘制一条折线, 横轴为行索引, 纵轴为对应位置的值, 绘制在一个子图里面, 使用python plot, 使用随机颜色进行区别添加显示和隐藏按钮, 可以对每条折线进行显示和隐藏 2. 代码 import numpy as np import matplotlib.pyplot as p…

软件心学格物致知篇(5)愿望清单上篇

愿望清单 前言 最近发现愿望清单是一个很有意思的词&#xff0c;结合自己的一些过往经验得到一点点启发。 我发现在众多领域都有东西想伪装成它。 比如一些企业的企业战略&#xff0c;比如客户提出的一些软件需求&#xff0c;比如一些系统的架构设计指标&#xff0c;比如一…

C语言动态内存讲解+通讯录2.0

文章目录 前文malloc和freecallocrealloc枚举常量的简单说明及使用 通讯录2.0动态开辟通讯录,满了就扩容保存数据和载入数据 通讯录2.0演示推荐好用的软件 前文 本文主要介绍动态开辟的几个函数,以及改进之前的通讯录。 我们局部变量等是在栈区上开辟空间的,而我们动态开辟的空…