综合练习dfs_1

1863. 找出所有子集的异或总和再求和

之前我们就做了到关于找集合子集的问题,但我们不需要记录路径上的数,求路径上数的异或和就可以。

class Solution {
    int path;
    int sum=0;
public:
    int subsetXORSum(vector<int>& nums) {
        dfs(nums,0);
        return sum;
    }
    void dfs(vector<int>&nums,int pos)
    {
        sum+=path;
        for(int i=pos;i<nums.size();i++)
        {
            path^=nums[i];
            dfs(nums,i+1);
            path^=nums[i];//恢复现场 A^A==0
        }
    }
};

47. 全排列 II

 之前做的全排列的题是不含重复的数字,但这道题有重复的数字且返回不重复的全排列。

选数时要满足两个条件:

1.在一条路径上同一个数只能选一次(不是值相同的数),和全排列1一样用check[]标记该数是否用过。

2.在同一个节点的所有分支中,相同值的元素只能选一次

eg.[1,1,1,2] 看似可以选4个数,但为了不重复第一个数只能选1_ _ _  2_ _ _。

当我们选了第一个1,第二个1第三个1就不能选了,因为以第2 3个1开头的数和第一个1都是值一样的。

所以我们选数时1.该数没有被用过 2.如果该数和前一个数相同也不能选,但看图中左下分支

3.如果和前一个数相同,但前一个数已经被用过了(可以理解为和其它数不在同一个分支上) 还是可以选的。(因为要判断和前一个数是否相同 所以先sort()排序)

4.i==0时 i-1会越界 只要i==0且该数每被用过就可以选

反过来我们也可以从不合法的分支入手,1.用过直接返回2.没用过 首先不是第一个数(因为没有i-1)该数和前一个相等 且前一个数没有被用过。

class Solution {
    vector<vector<int>> re;
    vector<int> path;
    bool check[9];
    int n;
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        n=nums.size();
        dfs(nums);
        return re;
    }
    void dfs(vector<int>& nums)
    {
        if(path.size()==n)
        {
            re.push_back(path);
            return;
        }
        for(int i=0;i<n;i++)
        {
            //只关心合法分支
            if(check[i]==false&&(i==0||nums[i]!=nums[i-1]||check[i-1]==true))
            {
                path.push_back(nums[i]);
                check[i]=true;
                dfs(nums);
                //回溯
                path.pop_back();
                check[i]=false;
            }
        }
    }
};

17. 电话号码的字母组合

1.先建立数字和字符串的映射关系。可以用字符串数组代替哈希表,数组前两个设为空。

2.传参数pos表示要找数字下标,用数字根据映射关系找到对应的字符串,遍历字符串进行递归。

3.处理特殊情况 digits=""没有数字直接返回空,进行dfs会push""字符串

class Solution {
    vector<string> re;
    vector<string> hash={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    string path;
public:
    vector<string> letterCombinations(string digits) {
        if(digits=="") return re;
        dfs(digits,0);
        return re;
    }
    void dfs(string digits,int pos)
    {
        if(path.size()==digits.size())
        {
            re.push_back(path);
            return;
        }
        //pos表示递归到第几层 有几个数字就有几层
        for(auto&ch:hash[digits[pos]-'0'])
        {
            path+=ch;
            dfs(digits,pos+1);
            //回溯
            path.pop_back();
        }
    }
};

22. 括号生成

递归返回的路径字符数肯定是n*2的,我们直接递归枚举出所有的情况,再进行剪枝剪去不能组成括号的情况:1.左括号数不能大于n 2.在递归过程中右括号的数不能大于左括号的数

递归终止条件:path==n*2 或者右括号数==n

class Solution {
    vector<string> re;
    string path;
public:
    vector<string> generateParenthesis(int n) {
        dfs(n,0,0);
        return re;
    }
    void dfs(int n,int l,int r)
    {
        if(r>l||l>n) return;//剪枝
        if(path.size()==n*2)
        {
            re.push_back(path);
            return;
        }
        path+="(";;
        dfs(n,l+1,r);
        path.pop_back();//恢复现场
        path+=")";
        dfs(n,l,r+1);
        path.pop_back();

    }
};

77. 组合

因为不能出现重复的eg.[1,2] [2,1],所以在递归时要进行剪枝 eg.2_ _ _选数时不能选自身 也不能选前面的数,只能选后面的数。

dfs函数参数pos传下一个要遍历的数

class Solution {
    vector<vector<int>> re;
    vector<int> path;
    int n,k;
public:
    vector<vector<int>> combine(int _n, int _k) {
        n=_n+1,k=_k;
        dfs(1);
        return re;
    }
    void dfs(int pos)
    {
        if(path.size()==k)
        {
            re.push_back(path);
            return;
        }
        for(int i=pos;i<n;i++)
        {
            path.push_back(i);
            dfs(i+1);//注意是i+1 不是pos+1
            //回溯
            path.pop_back();
        }
    }
};

i代表了当前递归层选择的数字,因此我们应该从i+1开始递归,确保下一次选择当前数字的后面。

494. 目标和

这道题和我们之前做的求子集时,用的方法一相同。对一个数选和不选,到这道题就是加和减。暴力枚举每种情况的加和减,统计符合条件的数。

1.传参数,pos指对第几个元素进行+/-

2.定义int path记录最终的和。(可以定义成全局的,也可以传参 定义成局部的,这样就不用恢复现场)

3.到最后一个数 path==target re++ 返回

1.path局部

class Solution {
    int count=0;

    int target;
public:
    int findTargetSumWays(vector<int>& nums, int _target) {
        target=_target;
        dfs(nums,0,0);
        return count;
    }
    void dfs(vector<int>& nums,int pos,int path)
    {
        if(pos==nums.size())
        {
            if(path==target) count++;
            return;
        }
        //1.+
        dfs(nums,pos+1,path+nums[pos]);

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

dfs(nums,pos+1,path+=nums[pos]); 不能写成+=,不能改变原本局部变量path的值

2.path全局

class Solution {
    int count=0;
    int path=0;
    int target;
public:
    int findTargetSumWays(vector<int>& nums, int _target) {
        target=_target;
        dfs(nums,0);
        return count;
    }
    void dfs(vector<int>& nums,int pos)
    {
        if(pos==nums.size())
        {
            if(path==target) count++;
            return;
        }
        //1.+
        path+=nums[pos];
        dfs(nums,pos+1);
        path-=nums[pos];
        //2.-
        path-=nums[pos];
        dfs(nums,pos+1);
        path+=nums[pos];
    }
};

39. 组合总和

数组每个元素不同,但可以重复选。

[2,3,5],第一个数选了2 后面还可以选2/3/5。

但第一个数选了3(数组中第二个元素),后面还可以选2吗?不能选,会出现重复情况。eg.[2,3,3] [3,2,3]。所以当我们选完一个数后,选下一个数时,只能选该数和其后面的数。

pos记录选到数组的第几个数

class Solution {
    vector<vector<int>> re;
    vector<int> path;
    int target;

public:
    vector<vector<int>> combinationSum(vector<int>& nums, int _target) {
        target = _target;
        dfs(nums, 0, 0);
        return re;
    }
    void dfs(vector<int>& nums, int sum, int pos) {
        if (sum == target) 
        {
            re.push_back(path);
            return;
        }
        //超过目标值||pos越界
        if (sum > target || pos == nums.size())
            return;
        for (int i = pos; i < nums.size(); i++) 
        {
            path.push_back(nums[i]);
            dfs(nums, sum + nums[i], i);
            path.pop_back();
        }
    }
};

注意可以选重复的数,所以要包含自身 dfs(nums,sum+nums[i],i) 不是i+1,i+1是只选该数后面的情况。

解法二:

我们可以先对选数组第一个数,从0开始累加直到大于目标值。0 2 4 6 8 再从小于目标值的情况中继续选数组第二个元素,同理也是不断累加直到大于目标值。

注意:在累积的过程中是不进行回溯的,在原基础上再加1次。等向上层返回时再进行回溯。

class Solution {
    vector<vector<int>> re;
    vector<int> path;
    int target;

public:
    vector<vector<int>> combinationSum(vector<int>& nums, int _target) {
        target = _target;
        dfs(nums, 0, 0);
        return re;
    }
    void dfs(vector<int>& nums, int sum, int pos) {
        if (sum == target) 
        {
            re.push_back(path);
            return;
        }
        if (sum > target || pos == nums.size())
            return;
        //将所有<=target情况push进去 <情况进入下一层累加 =记录并返回
        for(int k=0;sum+k*nums[pos]<=target;k++)
        {
            //k!=0进行push
            if(k) path.push_back(nums[pos]);
            dfs(nums,sum+k*nums[pos],pos+1);
        }
        //push几次就回溯几次 因为k==0 没有进行push所以这种情况不能进行pop 从k==1情况算起
        for(int k=1;sum+k*nums[pos]<=target;k++)
        {
            path.pop_back();
        }
    }
};

784. 字母大小写全排列

通过改变原字符串中的字母大小写,变成不同的字符串,问一共有多少种情况?
这个字符串里面有数字,我们可以用数组记录每个字母在字符串的下标,通过遍历数组间接遍历字符串中的字母。

遍历字符串字母,暴力枚举所有可能的情况。

pos记录要改变字母位置,改变完后选下一个要选改数后面的,选前面的会出现重复情况,传i+1。(i当前遍历的位置)

class Solution {
    vector<string> re;
    string path;
    vector<int> sub;
public:
    vector<string> letterCasePermutation(string s) {
        path=s;
        for(int i=0;i<s.size();i++) if(islower(s[i])||isupper(s[i])) sub.push_back(i);
        dfs(0);
        return re;
    }
    char toggle_case(char c)
    {
        if(isupper(c)) return tolower(c); //c+32变小写
        else if(islower(c)) return toupper(c); //c-32变大写
        else return c;
    }
    void dfs(int pos)
    {
        re.push_back(path);
        for(int i=pos;i<sub.size();i++)
        {
            path[sub[i]]=toggle_case(path[sub[i]]);//改变大小写
            dfs(i+1);
            path[sub[i]]=toggle_case(path[sub[i]]);//回溯
        }
        return;
    }
};

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

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

相关文章

【Python学习(五)——条件判断】

Python学习&#xff08;五&#xff09;——条件判断 本文介绍了条件判断&#xff0c;仅作为本人学习时记录&#xff0c;感兴趣的初学者可以一起看看&#xff0c;欢迎评论区讨论&#xff0c;一起加油鸭~~~ 心中默念&#xff1a;Python 简单好学&#xff01;&#xff01;&#x…

PPT加页码并改格式

如何快捷插入自定义 1、插入文本框&#xff0c;并处于输入状态 2、点击插入幻灯片编号的图标&#xff0c;就自动生成页码了 3、然后调整这个页码为想要的格式&#xff0c;到需要加页码的页面&#xff0c;将文本框复制过去就行了

Git 入门(一)

git 工作流如下&#xff1a; 命令如下&#xff1a; clone&#xff08;克隆&#xff09;: 从远程仓库中克隆代码到本地仓库checkout &#xff08;检出&#xff09;:从本地仓库中检出一个仓库分支然后进行修订add&#xff08;添加&#xff09;: 在提交前先将代码提交到暂存区com…

windows远程桌面无法连接,报错:“由于没有远程桌面授权服务器可以提供许可证,远程会话被中断。请跟服务器管理员联系”

windows远程桌面无法连接&#xff0c;报错&#xff1a;“由于没有远程桌面授权服务器可以提供许可证&#xff0c;远程会话被中断。请跟服务器管理员联系” 问题描述&#xff1a;解决方法&#xff1a;无法删除条目解决如下&#xff1a;正常激活详见&#xff1a;[RDS远程服务激活…

【JVM】总结篇-类的加载篇之 类的加载器 和ClassLoader分析

文章目录 类的加载器ClassLoader自定义类加载器双亲委派机制概念源码分析优势劣势如何打破Tomcat 沙箱安全机制JDK9 双亲委派机制变化 类的加载器 获得当前类的ClassLoader clazz.getClassLoader() 获得当前线程上下文的ClassLoader Thread.currentThread().getContextClassLoa…

蓝色简洁引导页网站源码

一款蓝色的简洁引导页&#xff0c;适合资源分发和网站备用引导。 1.源码上传至虚拟机或者服务器 2.绑定域名和目录 3.访问域名安装 4.安装完成后就行了 https://pan.quark.cn/s/b2d8b9c5dc7f https://pan.baidu.com/s/17h1bssUNhhR9DMyNTc-i9Q?pwd84sf https://caiyun.139.com…

Linux驱动开发(18):linux驱动并发与竞态

并发是指多个执行单元同时、并行执行&#xff0c;而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问 则很容易导致竞态。对于多核系统&#xff0c;很容易理解&#xff0c;由于多个CPU同时执行&#xff0c;多个CPU同时读、写共享资源时很容易造成竞态。…

docker中使用Volume完成数据共享

情景概述 在一个docker中&#xff0c;部署两个MySQL容器&#xff0c;假如它们的数据都存储在自己容器内部的data目录中。这样的存储方式会有以下问题&#xff1a; 1.无法保证两个MySQL容器中的数据同步。 2.容器删除后&#xff0c;数据就会丢失。 基于以上问题&#xff0c;容…

django StreamingHttpResponse fetchEventSource实现前后端流试返回数据并接收数据的完整详细过程

django后端环境介绍&#xff1a; Python 3.10.14 pip install django-cors-headers4.4.0 Django5.0.6 django-cors-headers4.4.0 djangorestframework3.15.2 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple 总环境如下&#xff1a; Package Version -…

R机器学习:神经网络算法的理解与实操,实例解析

神经网络算法是一种模仿生物神经网络&#xff08;尤其是人脑&#xff09;结构和功能的算法。它由大量相互连接的节点&#xff08;称为神经元&#xff09;组成&#xff0c;这些神经元组织成层&#xff0c;通过传递信号来处理信息。神经网络算法在机器学习、人工智能等领域中扮演…

供应链系统设计-供应链中台系统设计(七)- 商品中心设计篇

概述 上篇文章我们大致讲了一些商品中心相关的概念&#xff0c;例如&#xff1a;SPU、SKU、Item等等&#xff0c;在这里我们来简单的回顾一下&#xff1a; 商品概念的分层与定义&#xff1a; SPU&#xff08;Standard Product Unit&#xff09;&#xff1a;代表产品系列或产品…

人工智能在SEO中的应用与关键词优化策略

内容概要 随着科技的迅猛发展&#xff0c;人工智能在搜索引擎优化&#xff08;SEO&#xff09;中的应用逐渐成为业界关注的热点。AI技术不仅可以有效提高关键词的优化策略&#xff0c;还能在提升内容效率、增强用户体验方面发挥重要作用。通过对相关技术的深入探讨&#xff0c…

EPS32基础篇开发

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 开发 EPS32基础篇 前言一、GPIO输入输出GPIO可设置一下4种状态代码示例&#xff1a;检测按键&#xff0c;按下时&#xff1a;LED亮&#xff0c;松开时&#xff0c;LED灭 二、…

Backend - C# 的日志 NLog日志

目录 一、注入依赖和使用 logger 二、配置记录文件 1.安装插件 NLog 2.创建 nlog.config 配置文件 3. Programs配置日志信息 4. 设置 appsettings.json 的 LogLevel 5. 日志设定文件和日志级别的优先级 &#xff08;1&#xff09;常见的日志级别优先级 &#xff08;2&…

【游戏设计原理】47 - 超游戏思维

对于这条原理&#xff0c;我首先想到的是开放世界&#xff0c;或者探索性游戏&#xff0c;这是最能包容各类玩家的游戏类型。这类游戏定义了基本规则&#xff0c;玩家的可操作性很强。就像上图里的沙池一样&#xff0c;里面有滑梯&#xff0c;是规则性比较明确的&#xff0c;而…

24年无人机行业资讯 | 12.23-12.29

24年无人机行业资讯 | 12.23-12.29 1、 国家发改委新设低空经济司&#xff0c;助力低空经济规范发展2、商务部支持无人机民用国际贸易&#xff0c;强调出口管制与安全并重3、滨州高新区首架无人机成功下线4、 2025第九届世界无人机大会筹备推进会顺利召开5、2024年世界无人机竞…

【专题】2024年出口跨境电商促销趋势白皮书报告汇总PDF洞察(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p38722 在当今全球化加速演进、数字经济蓬勃发展的大背景下&#xff0c;跨境电商行业正以前所未有的态势重塑国际贸易格局&#xff0c;成为各方瞩目的焦点领域。 根据亚马逊发布的《2024年出口跨境电商促销趋势白皮书》&#xff0c;…

SMMU软件指南之系统架构考虑

安全之安全(security)博客目录导读 目录 5.1 I/O 一致性 5.2 客户端设备 5.2.1 地址大小 5.2.2 缓存 5.3 PCIe 注意事项 5.3.1 点对点通信 5.3.2 No_snoop 5.3.3 ATS 5.4 StreamID 分配 5.5 MSI 本博客介绍与 SMMU 相关的一些系统架构注意事项。 5.1 I/O 一致性 如…

mysql自定义安装

1、下载安装包 我是在windows上安装&#xff0c;所以选择“Mysql Installer for Windows” 2、安装mysql 双击“mysql-installer-community-8.0.40.0.msi”&#xff0c;开始启动安装 这里选择安装项&#xff0c;这里只选择了两项。workbench是图形化管理工具&#xff0c;比较吃…

Python、R用深度学习神经网络组合预测优化能源消费总量时间序列预测及ARIMA、xgboost对比...

全文链接&#xff1a;https://tecdat.cn/?p38726 分析师&#xff1a;Qingxia Wang 在能源领域&#xff0c;精准预测能源消费总量对制定合理能源战略至关重要。当前&#xff0c;能源消费预测分析主要运用单一模型&#xff08;如灰色预测法、时间序列分析法等&#xff09;和组合…