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

文章目录

  • 岛问题
  • 汉诺塔问题
  • 牛群繁衍数量问题
  • 求字符串的全部子序列
  • 字符串的全排列
  • 数字的全排列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移动到Bmove(pos1, pos3); //将A位置上剩余的盘子经过B移动到CHanoi(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个;.'初始化ansans[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.rhkb.cn/news/142928.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

创建线程的4种方法

目录 一.前言 1.关于进程调度 (1)为什么要调度? (2)调度的真正对象 (3)调度的资源 2.线程 (1).线程的写法 (2)线程创建的方法 1.继承Thread (1)使用继承Thread,重写run的方式来创建线程 (2)继承Thread,使用匿名内部类 2.实现Runnable (1)使用实现Runnable,重写run…

自定义ElementPlus主题颜色

构建工具采用Vite CSS预处理器采用Sass 一.准备定制化的样式文件 1.安装Sass npm i sass -D 2.创建好文件目录 3.书写样式 ElementPlus默认样式. //index.scss/* 只需要重写你需要的即可 */ forward element-plus/theme-chalk/src/common/var.scss with ($colors: (prim…

pytorch固定随机数中种子

1、添加到yolov7的utils/general.py文件最下面 import pkg_resources as pkg def check_version(current0.0.0, minimum0.0.0, nameversion , pinnedFalse, hardFalse, verboseFalse):# Check version vs. required versioncurrent, minimum (pkg.parse_version(x) for x in …

【Verilog 教程】6.6Verilog 仿真激励

关键词&#xff1a;testbench&#xff0c;仿真&#xff0c;文件读写 Verilog 代码设计完成后&#xff0c;还需要进行重要的步骤&#xff0c;即逻辑功能仿真。仿真激励文件称之为 testbench&#xff0c;放在各设计模块的顶层&#xff0c;以便对模块进行系统性的例化调用进行仿真…

c#用Gnuplot画图源码

直接调用这个类即可&#xff0c;需要下载个GnuPlot安装下。 // Author: Leonardo Tazziniusing System; using System.Diagnostics; using System.Drawing; using System.IO; using System.Windows.Forms;/// <summary> /// Tested with Gnuplot 5.2 /// </summary&g…

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

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

类和对象:运算符重载

本篇文章来介绍一下C中的运算符重载&#xff0c;以及与运算符重载有关的三个默认默认成员函数&#xff1a;赋值运算符重载&#xff0c;普通对象取地址与const对象取地址操作符重载&#xff0c;也就是下面图片中6个默认成员函数的后三个&#xff0c;前三个默认成员函数在之前文章…

【go语言】结构体

结构体 结构体定义 type name struct{value1 type1value2 type2...... }组成结构体的数据称为字段&#xff0c;每一个字段有一个类型和一个名字&#xff0c;每一个字段的名字必须唯一&#xff0c;字段的类型任意。 创建结构体 type myStruct struct{i1 intf1 float32str st…

HDLBits-Edgedetect

刚开始写的代码如下&#xff1a; module top_module (input clk,input [7:0] in,output [7:0] pedge );reg [7:0] in_pre;always (posedge clk)begin in_pre < in;endassign pedge in & ~in_pre; endmodule但是提交结果是错误的。猜想原因如下&#xff1a; assign p…

某音网页端 X-Bogus 参数

逆向目标 目标&#xff1a;某音网页端用户信息接口 X-Bogus 参数 接口&#xff1a;aHR0cHM6Ly93d3cuZG91eWluLmNvbS9hd2VtZS92MS93ZWIvdXNlci9wcm9maWxlL290aGVyLw 什么是 JSVMP&#xff1f; JSVMP 全称 Virtual Machine based code Protection for JavaScript&#xff0c;即 …

【网络八股】TCP八股

网络八股 请简述TCP/IP模型中每层的作用&#xff0c;典型协议和典型设备介绍一下三次握手的过程介绍一下四次挥手的过程必须三次握手吗&#xff0c;两次不行吗&#xff1f;为什么ACK数据包消耗TCP的序号吗三次握手中可以携带应用层数据吗四次挥手时&#xff0c;可以携带应用层数…

crypto:丢失的MD5

题目 得到一个md5.py 运行一下&#xff0c;发现报错&#xff0c;修改一下 运行之后又报错 报错原因是算法之前编码 正确的代码为 import hashlib for i in range(32,127):for j in range(32,127):for k in range(32,127):mhashlib.md5()m.update((TASC chr(i) O3RJMV c…

【Java SE】Lambda表达式

目录 ♫什么是Lambda表达式 ♫Lambda表达式的语法 ♫函数式接口 ♫Lambda表达式的使用 ♫变量捕获 ♫ Lambda表达式在集合中的使用 ♪Collection的foreach()&#xff1a; ♪List的sort()&#xff1a; ♪Map的foreach() ♫什么是Lambda表达式 Lambda 表达式是 Java SE 8中一个…

SpringMVC 学习(二)Hello SpringMVC

3. Hello SpringMVC (1) 新建 maven 模块 springmvc-02-hellomvc (2) 确认依赖的导入 (3) 配置 web.xml <!--web/WEB-INF/web.xml--> <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xmlns.jcp.org/xml/ns/javaee…

通用CI/CD软件平台TeamCity推出代理终端功能,谁能从中获益?

JetBrains官方在TeamCity中推出代理终端&#xff1a;这项新功能专门用于帮助用户轻松查看代理上的系统日志、检查已安装的软件&#xff0c;以及直接从 TeamCity 的 UI 调试特定代理问题。 TeamCity是一个通用的 CI/CD 软件平台&#xff0c;可以实现灵活的工作流、协作和开发做…

抖音短视频seo矩阵系统源代码开发系统架构及功能解析

短视频seo源码&#xff0c;短视频seo矩阵系统底层框架上支持了从ai视频混剪&#xff0c;视频批量原创产出&#xff0c;云存储批量视频制作&#xff0c;账号矩阵&#xff0c;视频一键分发&#xff0c;站内实现关键词、短视频批量搜索排名&#xff0c;数据统计分类多功能细节深度…

深入MySQL数据库进阶实战:性能优化、高可用性与安全性

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 MySQL是世界上最流行的开…

ruoyi-nbcio增加websocket与测试页面

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 为了后面流程发起等消息推送&#xff0c;所以需要集成websocket。 1、后端增加websoket支持 首先在framework模块里的pom.xml增加websocket <dependency…

Element UI搭建首页导航和左侧菜单以及Mock.js和(组件通信)总线的运用

目录 前言 一、Mock.js简介及使用 1.Mock.js简介 1.1.什么是Mock.js 1.2.Mock.js的两大特性 1.3.Mock.js使用的优势 1.4.Mock.js的基本用法 1.5.Mock.js与前端框架的集成 2.Mock.js的使用 2.1安装Mock.js 2.2.引入mockjs 2.3.mockjs使用 2.3.1.定义测试数据文件 2…

如何优化网站排名(百度SEO指南与优化布局方法)

百度SEO指南介绍&#xff1a;蘑菇号-www.mooogu.cn 首先&#xff0c;为了提高网站的搜索引擎优化排名&#xff0c;需要遵循百度SEO指南的规则和标准。这包括使用符合规范的网站结构、页面内容的质量和与目标用户相关的关键词。避免使用非法技术和黑帽SEO的方法。 增加百度SEO…