C++递归算法处理岛屿问题详解

目录
  • 岛屿问题定义
  • 例题一-岛屿的数量
  • 例题二-岛屿的周长

岛屿问题定义

岛屿问题是指用二维数组进行模拟, 1的位置表示陆地, 0的位置表示海洋。岛屿是指 被水(0)包围的陆地(1) 如下图所示:

岛屿问题是一道典型的递归问题(一位大佬曾说将岛屿问题看成是4叉树,我觉得这个比喻非常好), 对每个陆地位置, 我们需要递归地检测它的上下左右位置是不是陆地。

下面我们来写一下对岛屿问题的递归模板:

    public void dfs(char[][] grid, int m, int n){
    	// 位置越界 或者 该位置已经被遍历过
        if(isBeyond(grid, m, n) || grid[m][n] == 2){
            return;
        }
        // 相应操作
        ........
        // 记录已经遍历过位置
        grid[m][n] = '2';
		// 递归遍历该陆地位置的上下左右位置
        dfs(grid, m-1, n);
        dfs(grid, m+1, n);
        dfs(grid, m, n-1);
        dfs(grid, m, n+1);
    }
	// 检测越界的函数
    boolean isBeyond(char[][] grid, int m, int n){
        if(m < 0 || m>=grid.length || n<0 || n>=grid[0].length){
            return true;
        }
        return false;
    }

这里说明一下,岛屿问题中的备忘录问题,为什么在递归的过程中需要建立这样一个备忘录,我们可以看如下图解:

如果不建立备忘录,在递归过程中,可能会出现同一位置被多次递归调用的情况,这样增加了时间复杂度

备忘录实现方法 : 本题的备忘录实现非常简单, 只需将已经遍历过的位置的值修改为2即可

例题一-岛屿的数量

题目描述: 求一个二维数组中存在的岛屿数量

对本题我们直接调用上述模板即可

class Solution {
    public int numIslands(char[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int ans = 0;
        for(int i=0; i<m; i++){
            for(int j=0; j<n;j++){
                if(grid[i][j] == '1'){
                    // 递归过程中将属于同一岛屿的位置标记为2,保证属于同一岛屿的陆地1位置不会重复进入循环
                    dfs(grid, i, j);
                    ans++;
                }
            }
        }
        return ans;
    }
    public void dfs(char[][] grid, int m, int n){
        if(isBeyond(grid, m, n)){
            return;
        }
        if(grid[m][n] != '1'){
            return;
        }
        grid[m][n] = '2';
        dfs(grid, m-1, n);
        dfs(grid, m+1, n);
        dfs(grid, m, n-1);
        dfs(grid, m, n+1);
    }
    boolean isBeyond(char[][] grid, int m, int n){
        if(m < 0 || m>=grid.length || n<0 || n>=grid[0].length){
            return true;
        }
        return false;
    }
}

例题二-岛屿的周长

ps:输入保证只有一个岛屿

分析:

我们可以分析每一个陆地元素,对结果的贡献度,如下图解,经过分析可得,当陆地与海洋接壤一次或者越界一次对岛屿总周长的贡献度+1

代码

class Solution {
    // 从一个陆地方块走向一个非陆地方块,就将岛屿面积加1
    public int islandPerimeter(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int perimeter = 0;
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if(grid[i][j] == 1){
                    // 因为只有一个岛屿,直接返回即可
                    return getPerimeter(grid, i, j);
                }
            }
        }
        return 0;
    }
    public int getPerimeter(int[][] grid, int m, int n){
        // 走到非陆地方块,返回共享度1
        if(isBeyond(grid, m, n) || grid[m][n] == 0){
            return 1;
        }
        // 走到遍历过方块返回0
        if(grid[m][n] == 2){
            return 0;
        }
        // 标记已经遍历过节点
        grid[m][n] = 2;
        return getPerimeter(grid, m-1, n)
        + getPerimeter(grid, m+1, n)
        + getPerimeter(grid, m, n-1)
        + getPerimeter(grid, m, n+1);
    }
    boolean isBeyond(int[][] grid, int m, int n){
        if(m < 0 || n < 0 || m >= grid.length || n >= grid[0].length){
            return true;
        }
        return false;
    }
}

到此这篇关于C++递归算法处理岛屿问题详解的文章就介绍到这了,更多相关C++岛屿问题内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 超详细解析C++实现快速排序算法的方法

    目录 一.前言 1.分治算法 2.分治算法解题方法 二.快速排序 1.问题分析 2.算法设计 3.算法分析 三.AC代码 一.前言 1.分治算法 快速排序,其实是一种分治算法,那么在了解快速排序之前,我们先来看看什么是分治算法.在算法设计中,我们引入分而治之的策略,称为分治算法,其本质就是将一个大规模的问题分解为若干个规模较小的相同子问题,分而治之. 2.分治算法解题方法 1.分解: 将要解决的问题分解为若干个规模较小.相互独立.与原问题形式相同的子问题. 2.治理: 求解各个子问题.由于各个子

  • Java C++算法题解leetcode801使序列递增的最小交换次数

    目录 题目要求 思路:状态机DP 实现一:状态机 Java C++ Rust 实现二:滚动数组 Java C++ Rust 总结 题目要求 思路:状态机DP 实现一:状态机 Java class Solution { public int minSwap(int[] nums1, int[] nums2) { int n = nums1.length; int[][] f = new int[n][2]; for (int i = 1; i < n; i++) f[i][0] = f[i][1]

  • C++算法实现leetcode 1252奇数值单元格数目

    目录 题目描述 整理题意 解题思路分析 具体实现 复杂度分析 代码实现 总结 题目描述 题目链接:1252. 奇数值单元格的数目 给你一个 m x n 的矩阵,最开始的时候,每个单元格中的值都是 0. 另有一个二维索引数组 indices,indices[i] = [ri, ci] 指向矩阵中的某个位置,其中 ri 和 ci 分别表示指定的行和列(从 0 开始编号). 对 indices[i] 所指向的每个位置,应同时执行下述增量操作: ri 行上的所有单元格,加 1 . ci 列上的所有单元格

  • C C++算法题解LeetCode1408数组中的字符串匹配

    目录 题目描述 整理题意 解题思路分析 优化 具体实现 复杂度分析 代码实现 暴力 暴力 + 优化 KMP 总结 题目描述 题目链接:1408. 数组中的字符串匹配 给你一个字符串数组 words ,数组中的每个字符串都可以看作是一个单词.请你按 任意 顺序返回 words 中是其他单词的子字符串的所有单词. 如果你可以删除 words[j] 最左侧和/或最右侧的若干字符得到 word[i] ,那么字符串 words[i] 就是 words[j] 的一个子字符串. 提示: 示例 1: 输入:wo

  • Java C++题解leetcode字符串轮转KMP算法详解

    目录 题目要求 思路一:双指针(模拟) Java C++ 思路二:子串 手写KMP Java dp C++ dp 调API Java C++ 总结 题目要求 思路一:双指针(模拟) Java class Solution { public boolean isFlipedString(String s1, String s2) { if (s1.length() != s2.length()) return false; int n = s1.length(); if (n == 0) retu

  • C++递归算法处理岛屿问题详解

    目录 岛屿问题定义 例题一-岛屿的数量 例题二-岛屿的周长 岛屿问题定义 岛屿问题是指用二维数组进行模拟, 1的位置表示陆地, 0的位置表示海洋.岛屿是指 被水(0)包围的陆地(1) 如下图所示: 岛屿问题是一道典型的递归问题(一位大佬曾说将岛屿问题看成是4叉树,我觉得这个比喻非常好), 对每个陆地位置, 我们需要递归地检测它的上下左右位置是不是陆地. 下面我们来写一下对岛屿问题的递归模板: public void dfs(char[][] grid, int m, int n){ // 位置越

  • Java递归算法详解(动力节点整理)

    递归算法是一种直接或者间接调用自身函数或者方法的算法.Java递归算法是基于Java语言实现的递归算法.递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解.递归算法对解决一大类问题很有效,它可以使算法简洁和易于理解.    递归算法解决问题的特点: 1)递归就是方法里调用自身.  2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口.  3)递归算法解题通常显得很简洁,但递归算法解题的运行效率较低.所以一般不提倡用递归算法设计程序.  4)在递

  • Python实例详解递归算法

    递归是一种较为抽象的数学逻辑,可以简单的理解为「程序调用自身的算法」. 维基百科对递归的解释是: 递归(英语:Recursion),又译为递回,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法.递归一词还较常用于描述以自相似方法重复事物的过程. 例如,当两面镜子相互之间近似平行时,镜中嵌套的图像是以无限递归的形式出现的.也可以理解为自我复制的过程. "递"是传递的意思,"归"是归还的意思,先把一个方法一层层传递下去,然后传递到最后一层再把结果归还回来. 比

  • 例题详解Java dfs与记忆化搜索和分治递归算法的使用

    目录 一.dfs(深度优先搜索) 1.图的dfs 2.树的dfs 二.记忆化搜索 1.普通递归:O(2^n) 2.记忆化搜索: O(n) 三.分治 四.算法题 1.dia和威严 示例 2.小红点点点 示例1 3.kotori和素因子 示例1 示例2 4.kotori和糖果 示例 一.dfs(深度优先搜索) 1.图的dfs /** * 深度优先搜索 * * @param node * @param set */ public void DFS(Node node, Set<Node> set)

  • java并发编程_线程池的使用方法(详解)

    一.任务和执行策略之间的隐性耦合 Executor可以将任务的提交和任务的执行策略解耦 只有任务是同类型的且执行时间差别不大,才能发挥最大性能,否则,如将一些耗时长的任务和耗时短的任务放在一个线程池,除非线程池很大,否则会造成死锁等问题 1.线程饥饿死锁 类似于:将两个任务提交给一个单线程池,且两个任务之间相互依赖,一个任务等待另一个任务,则会发生死锁:表现为池不够 定义:某个任务必须等待池中其他任务的运行结果,有可能发生饥饿死锁 2.线程池大小 注意:线程池的大小还受其他的限制,如其他资源池:

  • C语言数据结构之图的遍历实例详解

    C语言数据结构之图的遍历实例详解 输入一组顶点,建立无向图的邻接矩阵.输入一组顶点,建立有向图的邻接表.分别对无向图和有向图进行DFS(深度优先遍历)和BFS(广度优先遍历).写出深度优先遍历的递归和非递归算法.根据建立的有向图,判断该图是否是有向无环图,若是,则输出其一种拓扑有序序列. 实现代码: #include <stdio.h> #include <stdlib.h> #define MAX 20 typedef struct ArcNode{ int adjvex; st

  • java编程实现并查集的路径压缩代码详解

    首先看两张路径压缩的图片: 并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的 Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等. 使用并查集时,首先会存在一组不相交的动态集合 S={S 1 ,S 2 ,⋯,S k } ,一般都会使用一个整数表示集合中的一个元素. 每个集合可能包含一个或多个元素,并选出集合中的某个元素作为代表.每个集合中具体包含

  • Java版超大整数阶乘算法代码详解-10,0000级

    当计算超过20以上的阶乘时,阶乘的结果值往往会很大.一个很小的数字的阶乘结果就可能超过目前个人计算机的整数范围.如果需求很大的阶乘,比如1000以上完全无法用简单的递归方式去解决.在网上我看到很多用C.C++和C#写的一些关于大整数阶乘的算法,其中不乏经典但也有很多粗糙的文章.数组越界,一眼就可以看出程序本身无法运行.转载他人文章的时候,代码倒是仔细看看啊.唉,粗糙.过年了,在家闲来蛋疼,仔细分析分析,用Java实现了一个程序计算超大整数阶乘.思想取自网上,由我个人优化和改进. 这个方法采用"数

  • PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解

    本文实例讲述了PHP实现二叉树深度优先遍历(前序.中序.后序)和广度优先遍历(层次).分享给大家供大家参考,具体如下: 前言: 深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次.要特别注意的是,二叉树的深度优先遍历比较特殊,可以细分为先序遍历.中序遍历.后序遍历.具体说明如下: 前序遍历:根节点->左子树->右子树 中序遍历:左子树->根节点->右子树 后序遍历:左子树->右子树->根节点 广度优先遍历:又叫层次遍历,从上往下对每一层依

  • 对python实现合并两个排序链表的方法详解

    输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 1.迭代方法 def Merge(self, pHead1, pHead2): p1, p2 = pHead1, pHead2 if p1 and p2: if p1.val < p2.val: head = p1 p1 = p1.next else: head = p2 p2 = p2.next cur = head elif p1: return p1 else: return p2 while p

随机推荐