【递归、搜索与回溯】综合练习二

news2024/12/26 23:05:34

综合练习二

  • 1.组合
  • 2.目标和
  • 3.组合总和
  • 4.字母大小写全排列

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.组合

题目链接:77. 组合

题目分析:

在这里插入图片描述
注意这道题结果是不能重复的。如1,2 和 2,1 虽然位置不同但是是同样的组合。
在这里插入图片描述

算法原理:
这样的题我们还是画出决策树,然后根据这棵树把所有细节分析清楚

在这里插入图片描述
每个位置都有4种选择,首先前面被选种的数字后面就不能再选了,如1,2 和2,1只是位置不同数都是一样的,因此还是重复。其次上每一层都是从上一层被选数字的后面一个开始选的。全局变量,一个ret记录最终结果,一个path记录每条路径的结果。递归函数,给一个pos,每一层都从pos位置开始往后选,dfs(pos)回溯 当递归结束往上返回要恢复现场pop掉path最后一个位置元素,剪枝 用pos控制开始的位置就是剪枝,递归出口 当path.size() == k 就可以把path放到ret里,然后结束本次递归。

在这里插入图片描述

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    int n_,k_;
public:
    vector<vector<int>> combine(int n, int k) {
        n_=n;k_=k;
        dfs(1);
        return ret;
    }

    void dfs(int pos)
    {
        if(path.size() == k_)
        {
            ret.push_back(path);
            return;
        }

        for(int i=pos;i<=n_;++i)
        {
            path.push_back(i);
            dfs(i+1);
            path.pop_back();//恢复现场
        }
    }
};

2.目标和

题目链接:494. 目标和

题目分析:

在这里插入图片描述

给一个数组,对数组每个数字前面添加 + 或者 - ,串联所有数字构成一个表达式,找出表达式和为目标值有多少种情况。

算法原理:
如果前面做过选子集的问题,这道题思想是一模一样的,找子集其中有一张方法是 这个数字 选or不选,这道题就是 这个数字前面 +or-。我们就根据这个画出决策树。
这里的步骤都不说了,和子集哪里的一模一样。最后到叶子节点这条路径的和加起来等于target,就是一种情况。

在这里插入图片描述
这里写代码有两种形式。

  1. path 是全局变量的时候的代码
  2. path 作为参数的代码

可以参考求二叉树所有路径那道题,这道题也是path作为全局变量和作为参数两种不同形式的代码。

path作为全局变量, 需要考虑回溯恢复现场。
path作为参数,不用考虑,因为在递归在向上返回的时候就已经帮助我们回溯恢复现场了。 path作为参数也是有回溯的不过是编译器就可以帮我回溯了。

如果path是一个单独的类型的话,如int类型,你会发现把它放在dfs参数里面写的话,代码比较简洁。如果path是一个数组类型的话,推荐使用全局变量

path作为全局变量的代码

class Solution {
    int ret,path,_target;
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        _target=target;
        dfs(nums,0);
        return ret;
    }

    void dfs(vector<int>& nums,int pos)
    {
        if(pos == nums.size())
        {
            if(path == _target) ++ret;
            return;
        }

        // 加法
        path+=nums[pos];
        dfs(nums,pos+1);
        path-=nums[pos];

        // 减法
        path-=nums[pos];
        dfs(nums,pos+1);
        path+=nums[pos];
    
    }
};

path作为参数的代码

class Solution {
    int ret,_target;
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        _target=target;
        dfs(nums,0,0);
        return ret;
    }

    void dfs(vector<int>& nums,int pos,long path)
    {
        if(pos == nums.size())
        {
            if(path == _target) ++ret;
            return;
        }

        // +
        dfs(nums,pos+1,path+nums[pos]);
        // -
        dfs(nums,pos+1,path-nums[pos]);


    }
};

3.组合总和

题目链接:39. 组合总和

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

注意这个数组中的数字,可以无限制重复被选择。但是结果不能有重复的就如下面2,2,3 和 2,3,2是属于同一种组合,只是位置不同罢了。

在这里插入图片描述
算法原理:
暴力枚举所有情况,根据不同的决策树,我们可以写出不同的代码。就比如

  1. 根据每个位置选什么的策略 画决策树
  2. 根据每个数选or不选 画决策树
  3. 考虑每个数用多少个 画决策树

解法一: 根据每个位置选什么的策略 画决策树

每个位置都有三种选择,因为一个数可以被无限制重复选择,所以递归到下一层还可以选。注意3,2 和 2,3 是一样的组合,前面选了后面就不要在选了。并且5,2 和5,3 和2,5 和3,5一样前面选了后面就不要选了。这是一种剪枝情况,还有当一路径的和sum都大于target了就可以结束递归了。这也是一种剪枝情况。

前面我们特别说明一下全局变量的和作为参数的在递归的区别。这里sum求每一条路径的和我们把它作为参数在递归函数中传递,这样每次回溯就不管sum了,而ret和path还是作为全局变量递归函数 我们发现每次都是从本身位置开始往下选,因此 dfs(nums,pos,sum),回溯 sum不用管,path等到递归返回后pop掉最后一个元素,剪枝已经在递归函数中作为pos传递了 ,递归出口 当sum == target 将path放到ret里然后返回,还有一种情况当sum>target不需要往下递归了和pos == nums.size()也不需要往下递归直接返回;
在这里插入图片描述

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    int aim;
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
            aim=target;
            dfs(candidates,0,0);
            return ret;
    }

    void dfs(vector<int>& candidates,int pos,int sum)
    {
        if(sum >= aim)
        {
            if(sum > aim) return;
            if(sum == aim) ret.push_back(path);
            return;
        }

        for(int i=pos;i<candidates.size();++i)
        {
            path.push_back(candidates[i]);
            dfs(candidates,i,sum+candidates[i]);
            path.pop_back();//恢复现场
        }
    }
};

解法二: 考虑每个数用多少个 画决策树

每个数可以被选择0-n次,当被选择n次的和都大于target就不能选选了,也就是说小于或者等于target的时候可以一直选这个数,然后往下递归也是和上面情况一样。这里有个细节要注意,当递归回去的时候,不要直接把path最后一个位置pop掉,而是等到这个数所有情况都选完了然后在pop掉path最后一个元素,因为这个数可以选1次、两次等等,如果选择一次往下走递归回来了你pop掉了,下一次path.push_back()就要放两个这个数,因为我们不先pop,等到最后这个数所有情况搞完返回上一层我们在把前面加入的所有这个数pop掉。

在这里插入图片描述

class Solution {
    vector<vector<int>> ret;
    vector<int> path;
    int aim;
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
            aim=target;
            dfs(candidates,0,0);
            return ret;
    }

    void dfs(vector<int>& candidates,int pos,int sum)
    {
        if(sum == aim)
        {
            ret.push_back(path);
            return;
        }

        if(sum > aim || pos == candidates.size()) return;

        // 枚举个数
        for(int k = 0; k * candidates[pos] + sum <= aim; k++)
        {
            if(k) path.push_back(candidates[pos]);
            dfs(candidates, pos + 1, sum + k * candidates[pos]);
        }

        // 恢复现场
        for(int k=1;k*candidates[pos]+sum <= aim;++k)
        {
            path.pop_back();
        }
    }
};

4.字母大小写全排列

题目链接:784. 字母大小写全排列

题目描述:

在这里插入图片描述
算法原理:

还是画出决策树,写代码。
对于每个字母我们都有两种选择,要么不变,要么变,小写变大写,大写变小写。对于数字我们不管它。其他的还是和前面的题一模一样。可以用全局path,也可以path当参数用。

在这里插入图片描述

class Solution {
    vector<string> ret;
    string path;
public:
    vector<string> letterCasePermutation(string s) {
        dfs(s,0);
        return ret;
    }

    void dfs(string& s,int pos)
    {
        if(pos == s.size())
        {
            ret.push_back(path);
            return;
        }

        char ch=s[pos];
        // 不改变
        path.push_back(ch);
        dfs(s,pos+1);
        path.pop_back();

        // 变
        if(ch < '0' || ch > '9')
        {
            if(islower(ch)) ch-=32;
            else ch+=32;

            path.push_back(ch);
            dfs(s,pos+1);
            path.pop_back();
        }

    }
};

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

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

相关文章

电脑剪贴板历史记录查看,让你的信息管理更加有序!

剪贴板是电脑中一个非常实用的功能&#xff0c;允许用户在不同的应用程序之间复制和粘贴文本、图像、文件等内容。然而&#xff0c;默认情况下&#xff0c;剪贴板只能存储最近一次复制的内容&#xff0c;这可能会限制我们的工作效率。幸运的是&#xff0c;电脑剪贴板历史记录查…

MySQL中实现行列转换的示例

在 MySQL 中进行行列转换&#xff08;即&#xff0c;将某些列转换为行或将某些行转换为列&#xff09;通常涉及使用条件逻辑和聚合函数。虽然 MySQL 没有像 Oracle/SQL Server 中的 PIVOT 和 UNPIVOT 那样的直接功能&#xff0c;但你可以通过结合 CASE 语句、UNION 或 UNION AL…

c语言哈夫曼中英文混合编码

一.需求文档 c语言实现哈夫曼编码 1.中文编码 2.英文编码 3.中英文混合编码 4.从文件读取进行编码 5.编码生成编码文件 6.从生成的编码文件进行解码 二.运行截图

香港优才计划中介避坑,深圳哪家优才中介有实力?

随着香港优才计划取消配额限制以来&#xff0c;优才计划递交申请量骤增&#xff0c;许多DIY的申请人在递交申请后&#xff0c;长时间未能收到审批结果&#xff0c;甚至有人等待了12个月之久仍对审批进展一无所知。 而一些有中介协助的申请人&#xff0c;在等待审批的过程中&am…

如何在WIndows虚拟机安装 macOS 黑苹果系统?

在本教程中&#xff0c;我们将介绍如何在虚拟机上安装 macOS 黑苹果系统。黑苹果系统是非苹果公司官方支持的 macOS 系统的非官方版本&#xff0c;可以在普通 PC 上运行。请注意&#xff0c;安装黑苹果系统可能违反苹果的许可协议&#xff0c;请自行承担风险。参考视频教程&…

二、C#基本语法

C#是一种面向对象的编程语言。在面向对象的程序设计方法中&#xff0c;程序由各种相互交互的对象组成。相同种类的对象通常具有相同的类型&#xff0c;或者说&#xff0c;是相同的class中。 例如&#xff0c;以rectangle&#xff08;矩形&#xff09;对象为例。它具有length和…

有声读物管理平台Booksonic-Air

老苏最近在听评书&#xff0c;所以想找个软件来管理和收听&#xff0c;找了一圈&#xff0c;感觉 Booksonic-Air 可能能满足老苏的需求。 什么是 Booksonic-Air &#xff1f; Booksonic-Air 是一个用于流式传输有声读物的服务器&#xff0c;是原始 Booksonic 服务器的后继者。…

docker镜像拉取K8s的calico,Pod报错Init:ImagePullBackOff及kubekey生成离线包报错error: Pipeline[ArtifactExportpipe的解决

配置k8s集群出现问题 起初以为是版本问题&#xff0c;最后比对了一下发现没有问题。使用 kubectl describe calico-node-mg9xh -n kube-system命令查看发现docker pull 镜像失败&#xff0c;但是docker国内镜像源早就配置过了。 猜测Docker的缓存可能会导致拉取镜像失败。尝试…

深入探究MySQL的B+树索引

一、索引概述 在MySQL中&#xff0c;索引是一种数据结构&#xff0c;它可以帮助数据库系统更快地检索数据。索引可以比作一本书的目录&#xff0c;它可以让我们不必翻阅整本书就能找到所需的信息。没有索引&#xff0c;MySQL必须从头到尾扫描整个表来找到相关的行&#xff0c;…

Hack The Box-Editorial

总体思路 SSRF->敏感信息泄露->CVE-2022-24439 信息收集&端口利用 nmap -sSVC editorial.htb目标机器开放22、80和1027端口&#xff0c;这里先查看80端口 进去后是一个图书收集界面&#xff0c;对网站进行扫描 dirsearch -u http://editorial.htb逐一访问 about界…

数据分析:微生物组差异丰度方法汇总

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 介绍 微生物数据具有一下的特点&#xff0c;这使得在做差异分析的时候需要考虑到更多的问题&…

示例:WPF中应用MarkupExtention自定义IValueConverter

一、目的&#xff1a;应用MarkupExtention定义IValueConverter&#xff0c;使得应用起来更简单和高效 二、实现 public abstract class MarkupValueConverterBase : MarkupExtension, IValueConverter{public abstract object Convert(object value, Type targetType, object …

白酒:茅台镇白酒的配餐建议与味觉体验

茅台镇白酒&#xff0c;以其与众不同的酿造工艺和卓着的品质&#xff0c;成为了中国白酒的代表之一。而云仓酒庄豪迈白酒&#xff0c;作为茅台镇的品牌&#xff0c;其配餐建议与味觉体验备受关注。 在品鉴云仓酒庄豪迈白酒时&#xff0c;配餐的选择对于整体味觉体验至关重要。…

17.零代码八爪鱼采集器数据采集与数据导出——如何导出不同格式数据和数据推送到数据库

首先&#xff0c;多数情况下免费版本的功能&#xff0c;已经可以满足绝大多数采集需求&#xff0c;想了解八爪鱼采集器版本区别的详情&#xff0c;请访问这篇帖子&#xff1a; 3.无代码爬虫八爪鱼采集器工具介绍——个人版本、团队版本的适用性_八爪鱼采集器 有单机版本吗-CSDN…

基于Django的博客系统之增加手机验证码登录(九)

需求文档 概述 实现基于Redis和第三方短信服务商的短信验证码登录功能。用户可以通过手机号码获取验证码&#xff0c;并使用验证码进行登录。 需求细节 用户请求验证码 用户在登录页面输入手机号码并请求获取验证码。系统生成验证码并将其存储在Redis中&#xff0c;同时通过…

二叉树的基础讲解

二叉树在遍历&#xff0c;查找&#xff0c;增删的效率上面都很高&#xff0c;是数据结构中很重要的&#xff0c;下面我们来基础的认识一下。(高级的本人还没学&#xff0c;下面的代码用伪代码或C语言写的)我会从树&#xff0c;树的一些专有名词&#xff0c;树的遍历&#xff0c…

Unity API学习之资源的动态加载

资源的动态加载 在实际游戏开发的更新换代中&#xff0c;随着开发的软件不断更新&#xff0c;我们在脚本中需要拖拽赋值的变量会变空&#xff0c;而要想重新拖拽又太花费时间&#xff0c;因此我们就需要用到Resources.Load<文件类型>("文件名")函数来在一开始…

【尚庭公寓SpringBoot + Vue 项目实战】租约管理(十四)

【尚庭公寓SpringBoot Vue 项目实战】租约管理&#xff08;十四&#xff09; 文章目录 【尚庭公寓SpringBoot Vue 项目实战】租约管理&#xff08;十四&#xff09;1、业务介绍2、逻辑介绍3、接口开发3.1、保存或更新租约信息3.2、根据条件分页查询租约列表3.3、根据ID查询租…

生成对抗网络——GAN(代码+理解)

目录 一、GAN模型介绍 二、GAN模型的训练过程 1. 初始化网络&#xff1a; 2. 训练判别器&#xff1a; 3. 训练生成器&#xff1a; 4. 重复步骤 2和步骤 3&#xff1a; 三、GAN实现 1. 模型结构 &#xff08;1&#xff09;生成器&#xff08;Generator&#xff09; &a…

动态 ETL 管道:使用非结构化 IO 将 AI 与 MinIO 和 Weaviate 的 Web

在现代数据驱动的环境中&#xff0c;网络是一个无穷无尽的信息来源&#xff0c;为洞察力和创新提供了巨大的潜力。然而&#xff0c;挑战在于提取、构建和分析这片浩瀚的数据海洋&#xff0c;使其具有可操作性。这就是Unstructured-IO 的创新&#xff0c;结合MinIO的对象存储和W…