多路递归的一些算法题

2024-04-27 19:44
文章标签 算法 递归 多路

本文主要是介绍多路递归的一些算法题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

首先我想讲一下,我对多路递归的理解吧,我认为多路递归就是循环中套回调,对于循环有几次就是几叉树,就好比我们常用的二叉树的dfs(node.left) 和 dfs(node.right)等前中后序遍历,也就是for (int i = 0; i < 2; i++) { TreeSet node = i == 0 ? node.left : node.right; dfs(node); }就是一个循环两次的for循环。实在无法理解就画图,好比二叉树画四个方格,1为递归出口,2为左指针,3为右指针,4回溯返回的结果

全排列

这一题也就是高中的排列组合,填空问题,n!。第一个空从n个数选一个,第二个空选除第一个空以外的数 n - 1 依次类推

全排列的链接

https://leetcode.cn/problems/VvJkup/icon-default.png?t=N7T8https://leetcode.cn/problems/VvJkup/

思路分析: 多路递归 + 回溯 + 剪枝 + 引入三个全局变量

多路递归:有几个数树分几个叉

回溯: 归的时候,返回我们修改前的状态

剪枝: 剪掉不需要的,比如遍历了A了下次就不要处理A了 

全局变量 result: 返回最终的结果

                temp:存放到叶子结点的值

                cheak:判断该元素是否枚举过了(剪枝)

这些说明代码注释里面都介绍了!

关于123的全排列的决策树 

public class MyTest1 {private List<List<Integer>> result;private List<Integer> temp;//存放枚举的结果private boolean[] cheak;//判断是否已经枚举过了public List<List<Integer>> permute(int[] nums) {result = new ArrayList<>();temp = new ArrayList<>();cheak = new boolean[nums.length];dfs(nums);return result;}//深搜(枚举) + 回溯(恢复现场) + 剪枝(cheak变量标记是否不需要遍历)private void dfs(int[] nums) {//递归出口if (temp.size() == nums.length){result.add(new ArrayList<>(temp));return;}for (int i = 0; i < nums.length; i++) {if (!cheak[i]) {temp.add(nums[i]);cheak[i] = true;dfs(nums);//递归完毕,进行回溯的时候说明已经是搞完了再往上返回//恢复现场cheak[i] = false;temp.remove(temp.size() - 1);}}}
}

子集

子集就是也是高中数学的基础知识,比如 1 2 的子集是{空集},{1},{2},{1,2},其实就是子序列也就是不去重的子集。

. - 力扣(LeetCode)

 思路分析:  这一题主要有两种解法,但是本博客就介绍一种

             解法一:双路递归的二叉分为选和不选

全局变量 + 多路递归 + 回溯  没有剪枝(因为只有选不选,不会出现枚举重复元素)

全局变量path: 递了总集的元素次结束,存放

二路递归:选或者不选,来分为二叉树

回溯:选的时候,往上归的时候要恢复现场

注释我都详解了。

             解法二:按照子集个数分,比如空集是个数为0

解法一的决策树

 解法二的决策树

注意这是解法一的代码,我并没有写解法二的代码 

package study2.day10;import java.util.ArrayList;
import java.util.List;//子集
public class MyTest5 {private List<Integer> path;//定义叶子结点存的内容private List<List<Integer>> result;//返回值public List<List<Integer>> subsets(int[] nums) {path = new ArrayList<>();result = new ArrayList<>();dfs(nums, 0);return result;}private void dfs(int[] nums, int index) {if (index == nums.length) {result.add(new ArrayList<>(path));return;}// 不选择当前元素dfs(nums, index + 1);// 选择当前元素path.add(nums[index]);dfs(nums, index + 1);path.remove(path.size() - 1);//回溯(恢复状态)}public static void main(String[] args) {new MyTest5().subsets(new int[]{1,2,3});}
}

 岛屿数量

岛屿数量也就是抱团1的数量,其中1表示地面,0表示海洋,这个是不是很像围棋,1没有气了就是一个岛了。这个题,其实和我写的博客(腐烂的苹果题目一样)但是我还是写错了,这个和那个唯一的区别,就是那个是同时扩散的bfs,这个是单个遍历的dfs

 http://t.csdnimg.cn/q9PFM  这是腐烂苹果博客的链接

 思路分析: 

                解法一:bfs

                解法二:dfs

解法一: bfs也就是借助了队列这个数据结构来保证回调的顺序

        1.创建一个队列(queue)用来保存回调的顺序

        2.遇到 1 入队列,并且标记这个元素已经被扫描过了 vis[i][j] = true

        3.队列不为空表示四周有陆地,继续将陆地并且没有被扫描过添加入队列继续遍历

解法二:dfs就是使用让计算机中的栈内存来当一个栈的数据结构供你使用

        1.遇到1,进入递归的dfs并且标记为被扫描

        2.和上述3一样就不一一介绍了

公共代码都一样只不过是调用的函数不一样: 

公共代码

 int[] dx = {0, 0, -1, 1};int[] dy = {1, -1, 0, 0};boolean[][] vis = null;//判断是否判断过int m = 0;char[][] grid = null;int n = 0;public int solve (char[][] grid) {this.grid = grid;m = grid.length;n = grid[0].length;int count = 0;vis = new boolean[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (!vis[i][j] && grid[i][j] == '1'){bfs(vis, i, j);//逐个遍历count++;}}}return count;}

解法一代码:

//解法一的bfs代码private void bfs(boolean[][] vis, int i, int j) {Queue<int[]> queue = new LinkedList<>();queue.offer(new int[]{i,j});vis[i][j] = true;while(!queue.isEmpty()){int[] arr = queue.poll();int a = arr[0], b = arr[1];for (int k = 0; k < 4; k++) {int x = a + dx[k], y = b + dy[k];if (x >= 0 && y >= 0 && x < m && y < n && !vis[x][y] &&  grid[x][y] == '1'){queue.offer(new int[]{x, y});vis[x][y] = true;}}}}

解法二代码:

 //深搜,全部的1都搜索private void dfs(boolean[][] vis, int i, int j) {vis[i][j] = true;for (int k = 0; k < 4; k++) {int x = i + dx[k], y = j + dy[k];if (x >= 0 && y >= 0 && x < m && y < n && !vis[x][y] &&  grid[x][y] == '1'){dfs(vis, x, y);}}}

总结

非常感谢您的支持和鼓励!制作博客确实需要付出很多心血,尤其是分享个人经验和解决问题的方法。如果我的回答对您有帮助,我会很高兴为您点个三连。另外,祝您周末愉快,愿您的每一天都充满快乐和成就!

这篇关于多路递归的一些算法题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

mysql递归查询语法WITH RECURSIVE的使用

《mysql递归查询语法WITHRECURSIVE的使用》本文主要介绍了mysql递归查询语法WITHRECURSIVE的使用,WITHRECURSIVE用于执行递归查询,特别适合处理层级结构或递归... 目录基本语法结构:关键部分解析:递归查询的工作流程:示例:员工与经理的层级关系解释:示例:树形结构的数

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Jackson库进行JSON 序列化时遇到了无限递归(Infinite Recursion)的问题及解决方案

《Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursion)的问题及解决方案》使用Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursi... 目录解决方案‌1. 使用 @jsonIgnore 忽略一个方向的引用2. 使用 @JsonManagedR

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.