【算法】递归(高阶题目) -随时补充

news2025/2/23 2:28:54

文章目录

  • 岛问题
  • 汉诺塔问题
  • 牛群繁衍数量问题
  • 求字符串的全部子序列
  • 字符串的全排列
  • 数字的全排列I
  • 数字的全排列II
  • N皇后II
  • N皇后I

岛问题

image-20220625202551222

递归的方法:

  • 遍历岛这个二维数组,如果当前数为1,则进入感染函数并将岛个数+1
  • 感染函数:其实就是一个递归标注的过程,它会将所有相连的1都标注成2 (去上下左右递归感染,直到把相连的一片1都感染)
    • 为什么要标注?这样就避免了遍历过程中的重复计数的情况,一个岛所有的1都变成了2后,遍历的时候就不会重复遍历了,当然也可以选择标注为其他值!
class Solution {
public:
    //感染函数:从(i,j)位置出发,把所有连成一片的'1',变成'2'
    //因为要对grid数组修改,以及为了减少拷贝,要传引用
    void infect(vector<vector<char>>& grid,int i ,int j)
    {
        //保证i和j范围的合法性  并且如果 当前位置不是'1'就返回
        if(i<0 || i == grid.size() || j<0 || j == grid[0].size() || grid[i][j] != '1')
        {
            return ;
        }
        //把当前位置感染为'2'
        grid[i][j] = '2';
        //去该位置的上下左右感染
        infect(grid,i-1,j);//左
        infect(grid,i+1,j);//右
        infect(grid,i,j+1);//下
        infect(grid,i,j-1);//上
    }
    int numIslands(vector<vector<char>>& grid) {
        int island = 0;
        //遍历二维数组
        for(int i = 0;i<grid.size();i++)
        {
            for(int j = 0;j<grid[0].size();j++)
            {
                //如果当前字符为1,岛的数量++,进入感染函数
                if(grid[i][j] == '1')
                {
                    island ++;//岛的数量++
                    infect(grid,i,j);//进入感染函数
                }
            }
        }    
        return island;//最后返回岛的数量
    }
};

时间复杂度分析:矩阵为m*n的规模,所以时间复杂度为:O(m*n)


汉诺塔问题

n个圆盘从下面开始按大小顺序摆放在A柱子上,规定:任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘,求最少的移动步骤

void move(char start, char end)
{
	printf("move:%c->%c\n", start, end);
}

//pos1:起始位置(A)    pos2:中转位置(B)    pos3:目标位置(C)  n:盘子数量 
void Hanoi(char pos1, char pos2, char pos3,int n)
{
	if (n == 1) //只有一个盘子,直接将盘子从起始位置移动到目标位置
	{
		move(pos1, pos3);
		return;
	}

	Hanoi(pos1, pos3, pos2, n - 1);//将A位置上的n-1个盘子经过C移动到B
	move(pos1, pos3); //将A位置上剩余的盘子经过B移动到C
	Hanoi(pos2, pos1, pos3, n - 1);//将B位置上的n-1个盘子通过A移动到C
}
int main()
{
	Hanoi('A', 'B', 'C', 3);
	return 0;
}

结论:假设有n个盘子,移动次数为: 2 n − 1   2^n -1  2n


牛群繁衍数量问题

母牛每年生一只母牛,新出生的母牛三年后也可以每年生一只母牛,假设母牛不会死,最开始母牛是A(就一个牛),求N年后母牛数量

方法:列出前几项找规律即可

  • F ( n ) F(n) F(n):第 n n n年的母牛数量,$F(n) = F(n-1) + F(n-3) $ :第N年的牛 = 前一年的牛 + 前三年的牛(三年前的牛现在就可以生)
int numOfCows(int n) 
{
    if(n<4)	return n;
    else return numOfCows(n - 1) + numOfCows(n - 3);
}

求字符串的全部子序列

子序列:在字符串当中任意的选取字符,可以不连续选取,最后形成的字符串称为子序列

//求字符串的子序列
void process(string str, int index, string path,vector<string>& ans)
{
	if (index == str.size())
	{
		ans.push_back(path);
		return;
	}
	process(str, index + 1, path + str[index], ans);//要当前index位置的字符,然后去index+1位置做选择
	process(str, index + 1, path, ans); //不要当前index位置的字符,去index+1位置做选择
}
//空串也算一种子序列=>全部字符都不要

如果要进行去重,那么可以把形成的子序列放到unordered_set当中

字符串的全排列

https://leetcode.cn/problems/zi-fu-chuan-de-pai-lie-lcof/)

image-20230915155535369

全排列:字符串当中的所有字符都得选取,只能决定每个字符的顺序不一样

定义一个递归函数: p r o c e s s ( 原始字符串 , 当前形成的字符串排列 , 记录字符是否被使用过 , 保存生成的字符串排列 ) process(原始字符串,当前形成的字符串排列,记录字符是否被使用过,保存生成的字符串排列) process(原始字符串,当前形成的字符串排列,记录字符是否被使用过,保存生成的字符串排列)

  • 为了方便进行去重,所以保存结果的结果集采用的数据结果是unordered_set

代码思路:

  • 如果当前形成的字符串排列和原始字符串的长度一样:表示已经生成了一个结果,将其放到结果集当中保存
  • 否则:遍历原始字符串当中的所有字符做选择,如果当前字符没有被选择过,那么就选中该字符,生成下一个字符,最后要记得进行回溯!
class Solution {
public:
    void process(string& str,string path,vector<bool>& visited,unordered_set<string>& ans)
    {
        if(path.size() == str.size()) 
        {
            ans.insert(path);
            return ;
        }
        int n = str.size();
        for(int i = 0;i<n;i++)//遍历原始字符串中的所有字符进行选择
        {
            if(!visited[i]) //当前i位置的字符没有被选择过
            {
                visited[i] = true;// 标记该字符已经被选中
                process(str,path+str[i],visited,ans); // 继续生成下一个字符
                visited[i] = false; // 取消该字符的标记,恢复现场
            }
        }
    }
    vector<string> permutation(string s) {
        vector<bool> visited(256,false);//字符是否有被选取
        unordered_set<string> ans;
        string tmp;
        process(s,tmp,visited,ans);
        return vector<string>(ans.begin(),ans.end());
    }
};

数字的全排列I

https://leetcode.cn/problems/permutations/description/

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案

image-20230915155526271

和上述字符串的全排列基本一致!

  • 1 <= nums.length <= 6,所以此时的记录数组只需要开辟7个空间即可标志每个位置的字符是否被选择
class Solution {
public:
    void process(vector<int>& nums,vector<int> path,vector<bool>& visited,vector<vector<int>>& ans)
    {
        if(path.size() == nums.size())
        {
            ans.push_back(path);
            return ;
        }
        int n = nums.size();
        for(int i = 0;i<n;i++)
        {
            if(!visited[i])
            {
                visited[i] = true;
                path.push_back(nums[i]);
                process(nums,path,visited,ans);
                visited[i] = false;
                path.pop_back(); //此处回溯的时候记得要在path当中弹出元素!!!
            }
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> visited(7,false);//i位置的字符是否被选择
        vector<vector<int>> ans;
        vector<int> v;
        process(nums,v,visited,ans);
        return ans;
    }
};

数字的全排列II

https://leetcode.cn/problems/permutations-ii/description/

给定一个可包含重复数字的序列 nums ,按任意顺序返回所有不重复的全排列

image-20230915162306596

做法:关键是去重!除重思路:先对nums数组进行sort,使得相同的数字都排在一起

思想:如果当前 i i i位置被使用过  或者  当前位置的元素和前一个位置的元素相同 && 前面一个元素没有被使用过 =>就不能选择当前位置的元素

if(visited[i] || (i>0 &&  nums[i] == nums[i-1] && !visited[i-1])) //去重
            continue;

class Solution {
public:
    void process(vector<int>& nums,vector<int> path,vector<bool>& visited,vector<vector<int>>& ans)
    {
        if(path.size() == nums.size())
        {
            ans.push_back(path);
            return ;
        }
        int n = nums.size();
        for(int i = 0;i<n;i++)
        { 
          if(visited[i] || (i>0 &&  nums[i] == nums[i-1] && !visited[i-1])) //去重
            continue;
          else 
          {
                visited[i] = true;
                path.push_back(nums[i]);
                process(nums,path,visited,ans);
                visited[i] = false;
                path.pop_back();
          }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<bool> visited(256,false);//字符是否有被选取
        vector<vector<int>> ans;
        vector<int> v;
        sort(nums.begin(),nums.end()); //先排序!!!!
        process(nums,v,visited,ans);
        return ans;
    }
};

N皇后II

https://leetcode.cn/problems/n-queens-ii/description/

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量

  • 即:任何两个皇后不同行、不同列、 也不在同一条斜线上

做法:

1.使用一个轨迹数组:保存每一行皇后存放的位置,每一行只填一个皇后就解决了皇后不同行的问题!只需再保证不同列和不在一条斜线

  • r e c o r d [ i ] = x record[i] = x record[i]=x:第 i i i行的皇后放在第 x x x列。有多少个皇后,轨迹数组就开辟多大

2.假设之前的某个皇后放在了 x 行 y 列 , x行y列, xy, 此时的皇后假设放在 甲行乙列 甲行乙列 甲行乙列,如果:y == 乙 (共列) || 甲-x的绝对值==乙-y的绝对值 (共斜线 => 坐标行相减的绝对值 == 坐标列相减的绝对值)​,那么此时这两个皇后就是打架的!

//判断现在i行的皇后如果放在j列上,和之前的皇后是否不打架
bool isValid(vector<int>& record, int i, int j)
{
	// 检查0~i-1行的皇后和此时放置在i行j列的皇后是否打架!
	for (int k = 0; k < i; k++)
	{
		//第k行的皇后 record[k]:第k行的皇后放在哪一列
		//共列 || 共斜线(坐标行相减的绝对值 == 坐标列相减的绝对值) -> 就打架
		if (j == record[k] ||abs(record[k] - j) == abs(i - k)) 
		{
			return false;
		}
	}
	//不打架! 当前第i行的皇后可以放在第j列!
	return true;
}

3.准备一个递归处理函数: p r o c e s s ( i n d e x , r e c o r d , n ) process(index,record,n) process(index,record,n):当前要在第 i n d e x index index行放置皇后,之前的皇后的位置都记录在了 r e c o r d record record轨迹数组当中,一共有 n n n行,返回后续有多少种放置方法

  • 只需要在 i n d e x index index行当中的所有列遍历一遍,尝试当前列是否可以放该皇后,保证跟之前所有的皇后不打架即可
int process(int index, vector<int>& record, int n)
{
    if (index == record.size())
    {
        //index到了终止位置:说明之前的皇后在不打架的情况下,所有的皇后填完了,那么之前做过的决定就是一种方法
        return 1;
    }
    int res = 0;
    //第index行的皇后放在哪一列呢?从第0列开始试一遍,只要和之前的皇后不打架就可以放!
    for (int cur = 0; cur < n; cur++)
    {
        //isValid:检查index行的皇后放在cur列是否会和之前的皇后打架
        if (isValid(record, index, cur))
        {
            //不打架,此时cur列可以放该皇后
            record[index] = cur;//当前皇后放在i行j列上

            res += process(index + 1, record, n);//统计当前皇后放在cur列,往后放皇后最后满足条件的方法数
        }
        //如果打架,就去考虑放在下一个位置
    }
    return res;
}
int totalNQueens(int n) {
    if (n < 1)
    {
        return 0;
    }
    vector<int> record(n);
    return process(0,record,n);
}

N皇后I

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案,'Q''.' 分别代表了皇后和空位。

  • 记录有效的情况下的n皇后的摆放情况

image-20230915165958971


针对上面的代码做修改:

  • 在递归函数当中多增加一个参数:用于保存有效的情况下的n皇后的摆放情况,当index == n的时候,之前做过的决定就是一种有效方法,在这个位置处理n皇后的摆放情况
  • 递归函数不需要返回方法数了,因为要的是摆放情况
//generateBoard:将当前n皇后的位置信息保存
void generateBoard(vector<int>& record,int n,vector<string>& res)
{
    //一行一行处理,先填满 '.' 再填皇后的列位置即record[index]为'Q'
    for(int index = 0;index<n;index++)
    {
        //ans:当前第index行的情况
        string ans(n,'.');//用n个;.'初始化ans
        ans[record[index]]='Q';//当前index行的皇后放在该行的record[index]列中
        res.push_back(ans);
    }
}
void process(int index, vector<int>& record, int n,vector<vector<string>>& result)
{
    if (index == record.size())
    {
        //index到了终止位置:说明之前的皇后在不打架的情况下,所有的皇后填完了
        //那么之前做过的决定就是一种有效方法
        vector<string> res;
        generateBoard(record,n,res);
        result.push_back(res);
    }
    //........................
}

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

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

相关文章

win11+wsl+git+cmake+x86gcc+armgcc+clangformat+vscode环境安装

一、安装wsl &#xff08;1&#xff09;打开power shell 并运行&#xff1a; Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform &#xff08;2&#xff0…

通过containerd部署k8s集群环境及初始化时部分报错解决

目录 一.基础环境配置&#xff08;每个节点都做&#xff09; 1.hosts解析 2.防火墙和selinux 3.安装基本软件并配置时间同步 4.禁用swap分区 5.更改内核参数 6.配置ipvs 7.k8s下载 &#xff08;1&#xff09;配置镜像下载相关软件 &#xff08;2&#xff09;配置kube…

用CRM系统协助销售跟踪客户

客户跟踪对销售来说非常重要&#xff0c;销售不及时跟进很容易导致潜在客户流失。那么对于销售来说&#xff0c;该如何做好客户跟踪呢&#xff1f;或许可以使用CRM客户管理系统。下面来说说&#xff0c;CRM系统如何协助销售跟踪客户&#xff1f; 智能联系客户提醒 销售人员通…

Django中的缓存

Django中的缓存 缓存的定义 定义: 缓存是-类可以更快的读取数据的介质统称&#xff0c;也指其它可以加快数据读取的存储方式。一般用来存储临时数据&#xff0c;常用介质的是读取速度很快的内存 意义:视图渲染有一定成本&#xff0c;数据库的频繁查询过高;所以对于低频变动的页…

蓝桥杯 题库 简单 每日十题 day11

01 质数 质数 题目描述 给定一个正整数N&#xff0c;请你输出N以内&#xff08;不包含N&#xff09;的质数以及质数的个数。 输入描述 输入一行&#xff0c;包含一个正整数N。1≤N≤10^3 输出描述 共两行。 第1行包含若干个素数&#xff0c;每两个素数之间用一个空格隔开&…

Day 03 python学习笔记

位运算 基于二进制的运算&#xff08;计算机的底层基于位运算&#xff09; 计算机最小单位&#xff1a;bit (比特/位/二进制) 1byte&#xff08;字节&#xff09; 8bit &#xff08; 0000 0000&#xff09; &&#xff1a;与 &#xff08;全真为真&#xff0c;一假则…

Linux eBPF介绍(二)

文章目录 一、如何搭建 eBPF 开发环境&#xff1f;二、开发第一个eBPF程序第一步&#xff1a;使用 C 开发一个 eBPF 程序第二步&#xff1a;使用 Python 和 BCC 库开发一个用户态程序第三步&#xff1a;执行 eBPF 程序 三、改进第一个 eBPF 程序&#xff1f; 作为 eBPF 最重大的…

java项目之列车票务信息管理系统(ssm源码+文档)

项目简介 列车票务信息管理系统实现了以下功能&#xff1a; 管理员&#xff1a;个人中心、用户管理、车票信息管理、购票指南管理、管理员管理、论坛管理、我的收藏管理、系统管理、订单管理。前台首页&#xff1a;首页、车票信息、购票指南、我的收藏管理、论坛信息、我的、…

基于YOLOv8模型的安全帽和背心检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的安全帽和背心检测系统可用于日常生活中检测与定位安全帽&#xff08;Hardhat&#xff09;和背心&#xff08;SafetyVest&#xff09;目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图…

Comparator 和 Comparable比较

Comparable是排序接口: 若一个类实现了Comparable接口&#xff0c;就意味着“该类支持排序”。 Comparator是比较器: 我们若需要控制某个类的次序&#xff0c;可以建立一个“该类的比较器”来进行排序。Comparable相当于“内部比较器”&#xff0c;而Comparator相当于“外部比较…

crypto:篱笆墙的影子

题目 下载压缩包解压后可得到提示文本 由题目名可以联想到可能是栅栏密码 借助解密工具可得

云原生微服务治理经典框架之Spring Cloud Alibaba核心技术与实战案例

系列文章目录 送书第一期 《用户画像&#xff1a;平台构建与业务实践》 送书活动之抽奖工具的打造 《获取博客评论用户抽取幸运中奖者》 送书第二期 《Spring Cloud Alibaba核心技术与实战案例》 文章目录 系列文章目录1、云原生如何做微服务治理&#xff1f;2、微服务治理框…

如何正确的清理C盘

如何正确清理C盘 Windows电脑操作系统一般是安装在磁盘驱动器的C盘中&#xff0c;一旦运行&#xff0c;便会产生许多垃圾文件&#xff0c;C盘空间在一定程度上都会越来越小。伴随着电脑工作的时间越久&#xff0c;C盘常常会提示显示其内存已不足。那么C盘容量不足对我们的电脑…

Java之线程的详细解析一

实现多线程 简单了解多线程【理解】 是指从软件或者硬件上实现多个线程并发执行的技术。 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程&#xff0c;提升性能。 并发和并行【理解】 并行&#xff1a;在同一时刻&#xff0c;有多个指令在多个CPU上同时执行…

NISP证书是什么?NISP含金量如何呢?

一、NISP是什么 NISP证书是国家信息安全水平考试&#xff08;National Information Security Test Program&#xff0c;简称NISP&#xff09;&#xff0c;是由中国信息安全测评中心实施培养国家网络空间安全人才的项目。由国家网络空间安全人才培养基地运营/管理&#xff0c;并…

硬件系统工程师宝典(42)-----耦合电容如何布局?

各位同学大家好&#xff0c;欢迎继续做客电子工程学习圈&#xff0c;今天我们继续来讲这本书&#xff0c;硬件系统工程师宝典。 上篇我们说到了对时序有要求的系统中如何正确使用蛇形走线&#xff0c;可以增加信号的延时&#xff0c;符合系统的时序要求。今天来说说电容去耦的…

项目进展(三)-电机驱动起来了,发现了很多关键点,也遇到了一些低级错误,

一、前言 昨天电机没有驱动起来&#xff0c;头发掉一堆&#xff0c;不过今天&#xff0c;终于终于终于把电机驱动起来了&#xff01;&#xff01;&#xff01;&#xff01;&#xff0c;特别开心&#xff0c;哈哈哈哈&#xff0c;后续继续努力完善&#xff01;&#xff01;&…

对象数组合并和去重

数组去重: 普通字符串/数字数组去重: 1. 利用Set的特性 > new Set(arr) 2. for遍历, indexOf判断是否存在 3. 利用对象去重, 因为对象的key有唯一性 数组合并: 可以使用克隆(克隆, 深克隆的那些方法) 对象数组去重: for循环, find或者findIndex判断是否存在, 然后不存…

通信协议:Uart的Verilog实现(下)

4、UART接收器 UART接收器负责接收串行比特流&#xff0c;去除起始位和停止位&#xff0c;并以并行格式将数据保存到与主机数据总线相连的寄存器里。接收器无法获得发送时钟&#xff0c;因此尽管数据以标准比特率到达&#xff0c;但数据未必与接收主机内的时钟同步。同步问题可…

增材云荣获2023世界制造业大会“安徽省重点工业互联网平台”称号

9月21日上午&#xff0c;2023世界制造业大会工业互联网专场发布会在合肥滨湖会展中心发布厅成功举办。会上发布了安徽省工业互联网领域的系列研究成果和创新应用案例。增材云平台深耕3D打印领域&#xff0c;整合3D打印产业链六大资源&#xff0c;以专业全面的技术助推行业快速发…