LeetCode 热题100 之 回溯1

news2025/1/16 12:47:38

1.全排列

在这里插入图片描述

  • 思路分析1(回溯):要生成一个不含重复数字的数组 nums 的所有可能全排列,我们可以使用回溯算法。这种算法通过递归的方法探索所有可能的排列组合,并在合适的时机进行回溯,确保不会遗漏任何排列。
  • 回溯算法
    • 使用一个current数组来存储当前排列;
    • 使用一个used布尔数组来标记哪些元素已经被加入到当前排列中;
    • 当current的大小等于nums的大小时,说明我们已经形成了一个完整的排列,可以将其添加到结果result中;
  • 递归与回溯
    • 递归的每一层代表选择一个数字加入current,并探索这个数字下的所有可能。
    • 一旦探索完成,我们需要“撤销”这个操作,即从current中移除该数字,并标记为未使用(回溯);

具体实现代码(详解版):

class Solution {
public:
    void backback(vector<int>& nums, vector<int>& current,
                  vector<vector<int>>& resut, vector<bool>& used) {
        // 如果当前排列的大小等于nums的大小,说明形成了一个完整的排列
        if (current.size() == nums.size()) {
            resut.push_back(current); // 将当前排列加入到结果中
            return;                   // 返回上一层
        }
        // 遍历所有数字
        for (int i = 0; i < nums.size(); i++) {
            // 如果nums[i]已经被使用,跳过该数字
            if (used[i])
                continue;

            // 标记nums[i]为已使用
            used[i] = true;
            current.push_back(nums[i]);

            // 继续继续下一个选择
            backback(nums, current, resut, used);

            // 回溯:移除当前数字并标记为未使用
            current.pop_back();
            used[i] = false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> current;
        vector<bool> used(nums.size(), false);

        backback(nums, current, result, used);
        return result;
    }
};

思路分析2(直接使用全排列函数)

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> res;
        sort(nums.begin(),nums.end());
        do{
           res.push_back(nums);
        }while(next_permutation(nums.begin(),nums.end()));
        return res;
    }
};

2.子集

在这里插入图片描述
思路分析(回溯):

  • 在每次调用backback时,先将子集current加入到result中;
  • 然后从当前索引indxe开始遍历nums,选择一个元素加入current再递归调用backback;
  • 递归结束后,移除最后一个元素(回溯),继续尝试其它可能的子集

具体实现代码(详解版):

class Solution {
public:
    void backback(vector<int>& nums, int index, vector<int>& current,
                  vector<vector<int>>& result) {
        // 将当前子集加入结果集中
        result.push_back(current);

        // 从当前所有开始,遍历每个元素
        for (int i = index; i < nums.size(); i++) {
            // 选择当前元素
            current.push_back(nums[i]);

            // 递归生成包含当前元素的子集
            backback(nums, i + 1, current, result);

            // 回溯,移除当前元素
            current.pop_back();
        }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> current;

        backback(nums, 0, current, result);
        return result;

        return result;
    }
};

3.电话号码的字母集合

在这里插入图片描述
思路分析:这是一个典型的回溯问题,因为我们需要在每一层递归中分别处理不同的数字,并组合出对应的字母。每个数字可以对应多个字母,因此我们可以使用递归或回溯法,将每一位数字的所有字母组合起来。

  • 回溯法的思路:
    • 递归构建路径:每次递归,我们处理一个数字,尝试将该数字对应的每个字母加入到当前组合中;
    • 深入递归:每选择一个字母后,将组合的路径传递到下一层递归中,处理下一个数字的选择;
    • 回溯撤销选择:在递归完成回退时,撤销最后一步操作,以便尝试当前数字对应其它字母的组合;

具体实现代码(详解版):

class Solution {
public:
    void backtracking(string& digits, int index,
                      unordered_map<char, string> phoneMap, string& current,
                      vector<string>& result) {
        // 收集结果
        if (index == digits.size()) {
            result.push_back(current);
            return;
        }
        // 获取当前数字对应的字母
        char digit = digits[index];
        const string& letters = phoneMap.at(digit);

        // 遍历当前数字的所有可能字母
        for (char letter : letters) {
            current.push_back(letter); // 选择一个字母
            backtracking(digits, index + 1, phoneMap, current, result); // 递归
            current.pop_back(); // 回溯
        }
    }
    vector<string> letterCombinations(string digits) {
        if (digits.empty())
            return {};

        // 数字到字母的映射
        unordered_map<char, string> phoneMap = {{'2', "abc"},
                                                {'3', "def"},
                                                {'4', "ghi"} ,{'5', "jkl"},
                                                {'6', "mno"},
                                                {'7', "pqrs"}, {'8', "tuv"},
                                                {'9', "wxyz"}};
        vector<string> result;
        string current;
        backtracking(digits, 0, phoneMap, current, result);
        return result;
    }
};

4.组合总和

在这里插入图片描述
这是一个典型的组合求和问题,在这里,我们需要找到所有可能的组合,使得数组中的元素之和等于给定的目标值 target。在组合中,数组中的每个元素可以被选择任意次,但组合中的元素顺序不影响结果的唯一性。
思路分析:这个问题可以通过回溯算法来解决。我们需要遍历每个元素,从当前元素开始进行递归计算,探索所有可能的组合。在递归过程中,我们不断减小目标值 target,直到 target 等于 0,这时说明找到了一组解。

  • 递归与回溯
    • 递归函数通过不断地选择当前数字并递归减小target的值,从而构建组合;
    • 如果target减少到0,说明找到一个组合,将其加入结果列表;
    • 如果 target 小于 0,则表示当前组合不符合要求,直接回溯。
  • 去重
    • 每次递归调用都可以从当前数字开始进行选择(包括重复选择当前数字),而不需要从头开始,避免重复组合的出现

具体实现代码(详解版):

class Solution {
public:
    void backtracking(vector<int>& candidates,int target,int index,vector<vector<int>>& result,vector<int>& current){
            //递归终止条件
            if(target ==0 ){
                result.push_back(current);//找到一个满足条件的组合,加入结果集
                return;
            }
        
            for(int i = index ; i < candidates.size() ; i ++){
                //选择当前元素
                if(candidates[i] <= target){//当前数字可以加入组合
                    current.push_back(candidates[i]);//做出选择
                    backtracking(candidates,target - candidates[i],i,result,current);
                    current.pop_back();//回溯
                }
            }
        }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> result;
        vector<int> current;
        backtracking(candidates,target,0,result,current);
        return result;
    }
};

5.括号生成

在这里插入图片描述

要生成所有可能的有效括号组合,我们可以使用回溯算法。对于给定的 n 对括号,生成的组合必须满足以下条件:

  • 括号对数匹配,即最终的左括号和右括号的数量相等;
  • 在生成工过程中,任何前缀的右括号数都不能超过左括号数,这样才能保证括号的有效性;

思路分析:

  • 递归和回溯:使用递归来构建括号组合字符串;
  • 控制左括号和右括号数量:
    • 如果左括号数量小于n,可以添加左括号;
    • 如果右括号数量小于左括号数量,可以添加右括号;
  • 递归终止条件:当左右括号的数量都等于n时,说明生成了一个有效的括号组合,将其加入结果集中。

具体实现代码(详解版):

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string> result;
        backtracking(result,"",0,0,n);
        return result;
    }
    void backtracking(vector<string>& result,string current,int open,int close,int max){
        if(current.size() == max * 2){//当生成的括号长度达到2 * n时,加入结果集
            result.push_back(current);
            return;
        }

        if(open < max){//只有当左括号数小于n时才能添加左括号
            backtracking(result,current + "(",open + 1 ,close,max);
        }
        if(close < open){//只有当右括号数小于左括号数才能添加右括号
            backtracking(result,current + ")",open,close + 1,max);
        }
    }
};

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

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

相关文章

笔记整理—linux驱动开发部分(4)驱动框架

内核中&#xff0c;针对每种驱动都设计了一套成熟的、标准的、典型的驱动框架&#xff0c;实现将相同部分实现&#xff0c;不同部分留出接口给工程师自行发挥。具有以下特点&#xff1a;①简单化&#xff1b;②标准化&#xff1b;③统一管控系统资源&#xff1b;④特定化接口函…

靠谷歌广告赚了100美刀,程序员可以照这个思路去干

复制网站盈利尝试&#xff1a;谷歌广告收入之路的挑战与反思 背景介绍 在互联网的浩瀚海洋中&#xff0c;网站复制现象屡见不鲜。近期&#xff0c;我尝试复制了一个名为网站B的核心代码&#xff0c;并成功发布了自己的网站。通过谷歌搜索引擎的优化&#xff08;SEO&#xff0…

Windows 10/11 设置锁屏密码的方法以及设置PIN密码

Windows 10/11 设置锁屏密码的方法 一、打开设置&#xff1a; 按 Win I 快捷键打开“设置”。 二、进入账户设置&#xff1a; 在设置窗口中点击“账户”。 三、选择登录选项&#xff1a; 在左侧菜单中选择“登录选项”。 四、添加密码&#xff1a; …

Python并发编程库:Asyncio的异步编程实战

Python并发编程库&#xff1a;Asyncio的异步编程实战 在现代应用中&#xff0c;并发和高效的I/O处理是影响系统性能的关键因素之一。Python的asyncio库是专为异步编程设计的模块&#xff0c;提供了一种更加高效、易读的并发编程方式&#xff0c;适用于处理大量的I/O密集型任务…

当软件质量遇上计划性报废:测试行业该如何应对?

那天&#xff0c;我像往常一样开车在路上&#xff0c;车窗外的风景飞快掠过。就在这时&#xff0c;我在听的一档播客里&#xff0c;突然提到了一个让我不得不停下来思考的词——“计划性报废”。这个词让我愣了一下&#xff0c;伴随着车轮的转动&#xff0c;我的思绪也随之转了…

【Seed-Labs】SQL Injection Attack Lab

Overview SQL 注入是一种代码注入技术&#xff0c;利用的是网络应用程序与数据库服务器之间接口的漏洞。当用户输入的信息在发送到后端数据库服务器之前没有在网络应用程序中进行正确检查时&#xff0c;就会出现这种漏洞。 许多网络应用程序从用户那里获取输入&#xff0c;然…

linux笔记(DNS)

一、概念 DNS&#xff08;Domain Name System&#xff09;DNS 是一种分布式网络目录服务&#xff0c;主要用于将人类易于记忆的域名&#xff08;如 www.example.com&#xff09;转换为计算机可识别的 IP 地址&#xff08;如 192.168.1.1&#xff09;。它就像是互联网的电话簿&a…

【计网】实现reactor反应堆模型 --- 框架搭建

没有一颗星&#xff0c; 会因为追求梦想而受伤&#xff0c; 当你真心渴望某样东西时&#xff0c; 整个宇宙都会来帮忙。 --- 保罗・戈埃罗 《牧羊少年奇幻之旅》--- 实现Reactor反应堆模型 1 前言2 框架搭建3 准备工作4 Reactor类的设计5 Connection连接接口6 回调方法 1 …

minikube 的 Kubernetes 入门教程--(五)

本文记录 Minikube 在 Kubernetes 上安装 WordPress 和 MySQL。 这两个应用都使用 PersistentVolumes 和 PersistentVolumeClaims 保存数据。 在深入这些步骤之前&#xff0c;先分享来自kubernetes.io教程。 链接>>使用持久卷部署 WordPress 和 MySQL | Kubernetes 获…

算法详解——链表的归并排序非递归解法

算法详解——链表的归并排序非递归解法 本文使用倍增法加上归并排序操作实现了对链表的快速排序&#xff0c;比起一般的递归式归并排序要节省空间并且实现要简单的多&#xff0c;比起一般的迭代式归并排序实现也要简单。 1. 题目假设 给定链表的头结点 head &#xff0c;请将其…

【网络-交换机】生成树协议、环路检测

路由优先级 路由优先级决定了在多种可达的路由类型中&#xff0c;哪种路由将被用来转发数据包。路由优先级值越低&#xff0c;对应路由的优先级越高&#xff0c;优先级值255表示对应的路由不可达。一般情况下&#xff0c;静态路由的优先级为1&#xff0c;OSPF路由优先级为110&a…

确定图像的熵和各向异性 Halcon entropy_gray 解析

1、图像的熵 1.1 介绍 图像熵&#xff08;image entropy&#xff09;是图像“繁忙”程度的估计值&#xff0c;它表示为图像灰度级集合的比特平均数&#xff0c;单位比特/像素&#xff0c;也描述了图像信源的平均信息量。熵指的是体系的混乱程度&#xff0c;对于图像而言&#…

数字后端零基础入门系列 | Innovus零基础LAB学习Day9

Module 16 Wire Editing 这个章节的学习目标是学习如何在innovus中手工画线&#xff0c;切断一根线&#xff0c;换孔&#xff0c;更改一条net shape的layer和width等等。这个技能是每个数字IC后端工程师必须具备的。因为项目后期都需要这些技能来修复DRC和做一些手工custom走线…

除草机器人算法以及技术详解!

算法详解 图像识别与目标检测算法 Yolo算法&#xff1a;这是目标检测领域的一种常用算法&#xff0c;通过卷积神经网络对输入图像进行处理&#xff0c;将图像划分为多个网格&#xff0c;每个网格生成预测框&#xff0c;并通过非极大值抑制&#xff08;NMS&#xff09;筛选出最…

ProCalun卡伦纯天然万用膏,全家的皮肤健康守护

受季节交替、生活环境变化、空气污染等方面因素的影响&#xff0c;加上作息不规律导致的免疫力降低&#xff0c;我们或多或少会出现一些如湿疹、痤疮、瘙痒之类的皮肤问题&#xff0c;且反复概率很高。很多人盲目用药&#xff0c;甚至诱发激素依赖性皮炎。所以近年来&#xff0…

Vue 自定义icon组件封装SVG图标

通过自定义子组件CustomIcon.vue使用SVG图标&#xff0c;相比iconfont下载文件、重新替换更节省时间。 子组件包括&#xff1a; 1. Icons.vue 存放所有SVG图标的path 2. CustomIcon.vue 通过icon的id索引对应的图标 使用的时候需要将 <Icons></Icons> 引到使用的…

wireshark工具使用

复制数据 1.右键展开整帧数据 2.复制“所有可见项目” mark标记数据 标记&#xff1a; 跳转&#xff1a; 保存成文件&#xff1a; 文件–>导出特定分组—>Marked packets only

【SpringCloud】SpringBoot集成Swagger 常用Swagger注解

概述&#xff1a;SpringBoot集成Swagger 常用Swagger注解 导语 相信无论是前端还是后端开发&#xff0c;都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力&#xff0c;经常来不及更新。其实无论是前…

Webserver(4.9)本地套接字的通信

目录 本地套接字 本地套接字 TCP\UDP实现不同主机、网络通信 本地套接字实现本地的进程间的通信&#xff0c;类似的&#xff0c;一般采用TCP的通信流程 生成套接字文件 #include<arpa/inet.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h&…

[spring源码]spring配置类解析

解析配置类 在启动Spring时&#xff0c;需要传入一个AppConfig.class给ApplicationContext&#xff0c;ApplicationContext会根据AppConfig类封装为一个BeanDefinition&#xff0c;这种BeanDefinition我们把它称为配置类BeanDefinition AnnotationConfigApplicationContext a…