LeetCode - 463. Island Perimeter(岛屿的周长)(规律/DFS/BFS)

22 篇文章 0 订阅
13 篇文章 0 订阅

LeetCode - 463. Island Perimeter(岛屿的周长)(规律/DFS/BFS)

  • 找规律
  • BFS
  • DFS

题目链接
题目

在这里插入图片描述

找规律

这个方法的思路就是:

  • 首先看如果没有相邻的方格的话,就是4 * (grid[i][j] == 1)的数量 ,记为island
  • 如果有相邻的,我们只需要遍历每一个,上下左右4个方向,有相邻的统计即可,最后用island - 这个数量即可;
class Solution {
    public int islandPerimeter(int[][] grid) {
        if (grid == null || grid.length == 0)
            return 0;
        int[][] dir = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
        int island = 0, neighbor = 0;
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    island++;
                    for (int k = 0; k < 4; k++) {
                        if (judge(grid, i + dir[k][0], j + dir[k][1]))
                            neighbor++;
                    }
                }
            }
        }
        return 4 * island - neighbor;
    }

    private boolean judge(int[][] grid, int i, int j) {
        if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length)
            return false;
        return grid[i][j] == 1;
    }
}

这种写法一点小小的改进就是,只判断四个方向中的两个,这样就可以少判断一个岛屿,但是neighbor就要*2 :

class Solution {
    public int islandPerimeter(int[][] grid) {
        if (grid == null || grid.length == 0)
            return 0;
        int island = 0, neighbor = 0;
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    island++;
                    if (i - 1 >= 0 && grid[i - 1][j] == 1)//检查上
                        neighbor++;
                    if (j + 1 < grid[0].length && grid[i][j + 1] == 1)
                        neighbor++;
                }
            }
        }
        return 4 * island - neighbor * 2; //注意这里是 * 2
    }
}

BFS

这题也可以使用BFS,但是这里要注意:

  • 在判断check函数中,没有加入vis[i][j]的判断,因为这会影响neighbor的统计
  • 因为neighbor的统计不依赖于 是否访问过这个方格,而是只看这个方格是否有相邻的方格
class Solution {

    private class Coordinate {
        public int x;
        public int y;

        public Coordinate(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public int islandPerimeter(int[][] grid) {
        if (grid == null || grid.length == 0)
            return 0;
        int[] x = {-1, 0, 1, 0};
        int[] y = {0, 1, 0, -1};
        Queue<Coordinate> queue = new LinkedList<>();
        boolean[][] vis = new boolean[grid.length][grid[0].length];
        int res = 0;
        Coordinate cur = null, next = new Coordinate(-1, -1);
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 0 || vis[i][j])
                    continue;
                queue.add(new Coordinate(i, j));  // add the start
                vis[i][j] = true;
                // begin the BFS
                while (!queue.isEmpty()) {
                    cur = queue.poll();
                    res += 4;
                    int neighbor = 0;
                    for (int k = 0; k < 4; k++) {
                        next.x = cur.x + x[k];
                        next.y = cur.y + y[k];
                        if (check(grid, next.x, next.y, vis)) {
                            if (!vis[next.x][next.y]) {
                                vis[next.x][next.y] = true;
                                queue.add(new Coordinate(next.x, next.y));
                            }
                            neighbor++;//无论是否 vis 都要++
                        }
                    }
                    res -= neighbor;
                }
            }
        }
        return res;
    }

    //注意这里 没有判断 !vis[i][j] 因为那样不能正确统计 count
    private boolean check(int[][] grid, int i, int j, boolean[][] vis) {
        return i >= 0 && i < grid.length && j >= 0 &&
                j < grid[0].length && grid[i][j] == 1;
    }
}

DFS

类似的,会DFS就行,但是也要和BFS一样,注意:

  • 虽然访问过了,但是还是要减去1的情况,也就是else if中的;
  • 没访问过,是,当然也要减去1
class Solution {

    int[] dirx = {-1, 0, 1, 0};
    int[] diry = {0, 1, 0, -1};
    boolean[][] vis;

    public int islandPerimeter(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0)
            return 0;
        int res = 0;
        vis = new boolean[grid.length][grid[0].length];
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1 && !vis[i][j])
                    res += dfs(grid, i, j);
            }
        }
        return res;
    }

    private int dfs(int[][] grid, int x, int y) {
        vis[x][y] = true;
        int edges = 4;
        for (int i = 0; i < 4; i++) {
            int nx = x + dirx[i];
            int ny = y + diry[i];
            if (check(grid, nx, ny)) {
                if (grid[nx][ny] == 1 && !vis[nx][ny]) {
                    edges += dfs(grid, nx, ny);
                    edges--;           // 因为有1也是相邻,所以要 -1 注意不是-2,因为只负责一边
                } else if (vis[nx][ny]) { // grid[nx][ny] == 1 && vis[nx][ny]   --> 这个也要,不要忘了
                    edges--;
                }
            }
        }
        return edges;
    }

    private boolean check(int[][] grid, int i, int j) {
        return i >= 0 && i < grid.length && j >= 0 && j < grid[0].length;
    }
}

改一下check函数,改写一下,和BFS更像,也阔以:

class Solution {

    int[] dirx = {-1, 0, 1, 0};
    int[] diry = {0, 1, 0, -1};
    boolean[][] vis;

    public int islandPerimeter(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0)
            return 0;
        int res = 0;
        vis = new boolean[grid.length][grid[0].length];
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1 && !vis[i][j])
                    res += dfs(grid, i, j);
            }
        }
        return res;
    }

    private int dfs(int[][] grid, int x, int y) {
        vis[x][y] = true;
        int edges = 4;
        for (int i = 0; i < 4; i++) {
            int nx = x + dirx[i];
            int ny = y + diry[i];
            if (check(grid, nx, ny)) {
                if (!vis[nx][ny]) {
                    edges += dfs(grid, nx, ny);
                }
                edges--;   //无论是否访问过都要 减去 1,  -1 注意不是-2,因为只负责一边
            }
        }
        return edges;
    }

    //这里改了
    private boolean check(int[][] grid, int i, int j) {
        return i >= 0 && i < grid.length && j >= 0 && j < grid[0].length && grid[i][j] == 1;
    }
}
### 回答1: 好的,我来用中文回复这个链接:https://leetcode-cn.com/tag/dynamic-programming/ 这个链接是 LeetCode 上关于动态规划的题目集合。动态规划是一种常用的算法思想,可以用来解决很多实际问题,比如最长公共子序列、背包问题、最短路径等等。在 LeetCode 上,动态规划也是一个非常重要的题型,很多题目都需要用到动态规划的思想来解决。 这个链接里包含了很多关于动态规划的题目,按照难度从简单到困难排列。每个题目都有详细的题目描述、输入输出样例、题目解析和代码实现等内容,非常适合想要学习动态规划算法的人来练习和提高自己的能力。 总之,这个链接是一个非常好的学习动态规划算法的资源,建议大家多多利用。 ### 回答2: 动态规划是一种算法思想,通常用于优化具有重叠子问题和最优子结构性质的问题。由于其成熟的数学理论和强大的实用效果,动态规划在计算机科学、数学、经济学、管理学等领域均有重要应用。 在计算机科学领域,动态规划常用于解决最优化问题,如背包问题、图像处理、语音识别、自然语言处理等。同时,在计算机网络和分布式系统中,动态规划也广泛应用于各种优化算法中,如链路优化、路由算法、网络流量控制等。 对于算法领域的程序员而言,动态规划是一种必要的技能和知识点。在LeetCode这样的程序员平台上,题目分类和标签设置十分细致和方便,方便程序员查并深入学习不同类型的算法。 LeetCode的动态规划标签下的题目涵盖了各种难度级别和场景的问题。从简单的斐波那契数列、迷宫问题到可以用于实际应用的背包问题、最长公共子序列等,难度不断递进且话题丰富,有助于开发人员掌握动态规划的实际应用技能和抽象思维模式。 因此,深入LeetCode动态规划分类下的题目学习和练习,对于程序员的职业发展和技能提升有着重要的意义。 ### 回答3: 动态规划是一种常见的算法思想,它通过将问题拆分成子问题的方式进行求解。在LeetCode中,动态规划标签涵盖了众多经典和优美的算法问题,例如斐波那契数列、矩阵链乘法、背包问题等。 动态规划的核心思想是“记忆化搜索”,即将中间状态保存下来,避免重复计算。通常情况下,我们会使用一张二维表来记录状态转移过程中的中间值,例如动态规划求解斐波那契数列问题时,就可以定义一个二维数组f[i][j],代表第i项斐波那契数列中,第j个元素的值。 在LeetCode中,动态规划标签下有众多难度不同的问题。例如,经典的“爬楼梯”问题,要求我们计算到n级楼梯的方案数。这个问题的解法非常简单,只需要维护一个长度为n的数组,记录到达每一级楼梯的方案数即可。类似的问题还有“零钱兑换”、“乘积最大子数组”、“通配符匹配”等,它们都采用了类似的动态规划思想,通过拆分问题、保存中间状态来求解问题。 需要注意的是,动态规划算法并不是万能的,它虽然可以处理众多经典问题,但在某些场景下并不适用。例如,某些问题的状态转移过程比较复杂,或者状态转移方程中存在多个参数,这些情况下使用动态规划算法可能会变得比较麻烦。此外,动态规划算法也存在一些常见误区,例如错用贪心思想、未考虑边界情况等。 总之,掌握动态规划算法对于LeetCode的学习和解题都非常重要。除了刷题以外,我们还可以通过阅读经典的动态规划书籍,例如《算法竞赛进阶指南》、《算法与数据结构基础》等,来深入理解这种算法思想。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值