岛屿的个数II - LintCode

204 篇文章 0 订阅

给定 n,m,分别代表一个2D矩阵的行数和列数,同时,给定一个大小为 k 的二元数组A。起初,2D矩阵的所有值均为 0,即该矩阵中只有海洋。二元数组有 k 个运算符,每个运算符有 2 个整数 A[i].x, A[i].y,你可通过改变矩阵网格中的A[[i].x],[A[i].y] 来将其由海洋改为岛屿。请在每次运算后,返回矩阵中岛屿的数量。

 注意事项
0 代表海,1 代表岛。如果两个1相邻,那么这两个1属于同一个岛。我们只考虑上下左右为相邻。

样例
给定 n = 3, m = 3, 二元数组 A = [(0,0),(0,1),(2,2),(2,1)].

返回 [1,1,2,2].

一刷,超时

#ifndef C434_H
#define C434_H
#include<iostream>
#include<vector>
#include<map>
#include<set>
using namespace std;
struct Point{
    int x;
    int y;
    Point() :x(0), y(0){}
    Point(int a, int b) :x(a), y(b){}
};
class Solution {
public:
    /**
    * @param n: An integer
    * @param m: An integer
    * @param operators: an array of point
    * @return: an integer array
    */
    vector<int> numIslands2(int n, int m, vector<Point> &operators) {
        // write your code here
        vector<int> res;
        vector<int> nums(n*m + 1, 0);
        for (int i = 0; i < operators.size(); ++i)
        {
            set<int> set;
            int pos = operators[i].x*m + operators[i].y + 1;
            nums[pos] = pos;
            for (int j = 1; j <= n*m; ++j)
            {
                if (pos != j&&nums[j]>0 && nums[pos] != nums[j])
                {
                    if (pos%m == 0)
                    {
                        if (j == pos + m || j == pos - m || j == pos - 1)
                            join(pos, j, nums);
                    }
                    else if ((pos - 1) % m == 0)
                    {
                        if (j == pos + m || j == pos - m || j == pos + 1)
                            join(pos, j, nums);
                    }
                    else
                    {
                        if (j == pos + m || j == pos - m || j == pos + 1 || j == pos - 1)
                            join(pos, j, nums);
                    }
                }
            }
            for (int k = 0; k <= n*m; ++k)
            {
                nums[k] = nums[nums[k]];
            }
            for (auto c : nums)
            {
                if (c > 0)
                    set.insert(c);
            }
            res.push_back(set.size());
        }
        return res;
    }
    int unionsearch(int root, vector<int> &nums)
    {
        int son, temp;
        son = root;
        while (root != nums[root])
            root = nums[root];
        while (son != root)
        {
            temp = nums[son];
            nums[son] = root;
            son = temp;
        }
        return root;
    }
    void join(int root1, int root2,vector<int> &nums)
    {
        int x, y;
        x = unionsearch(root1, nums);
        y = unionsearch(root2, nums);
        if (x <= y)
            nums[y] = x;
        else
            nums[x] = y;
    }
};
#endif

思路
构建数组nums表示所有位置对应岛屿的数字,初始化为0。遍历数组并将岛屿的值初始化为位置的值,此时岛屿数目+1,之后遍历此位置的邻接位置,若已经编号的岛屿,则将改岛屿的编号改为邻接岛屿编号,由于岛屿融合,岛屿的总数目-1。

#ifndef C434_H
#define C434_H
#include<iostream>
#include<vector>
using namespace std;
/*
* 岛屿的个数II
*
* 给定 n,m,分别代表一个2D矩阵的行数和列数,同时,给定一个大小为 k 的二元数组A。起初,2D矩阵的行数和列数均为 0,即该矩阵中只有海洋。二元数组有 k 个运算符,每个运算符有 2 个整数 A[i].x, A[i].y,你可通过改变矩阵网格中的A[i].x],[A[i].y] 来将其由海洋改为岛屿。请在每次运算后,返回矩阵中岛屿的数量。
* 注意事项
* 0 代表海,1 代表岛。如果两个1相邻,那么这两个1属于同一个岛。我们只考虑上下左右为相邻。
* 样例
* 给定 n = 3, m = 3, 二元数组 A = [(0,0),(0,1),(2,2),(2,1)].
* 返回 [1,1,2,2].
*/
struct Point{
    int x;
    int y;
    Point() :x(0), y(0){}
    Point(int a, int b) :x(a), y(b){}
};
class Solution {
public:
    /**
    * @param n: An integer
    * @param m: An integer
    * @param operators: an array of point
    * @return: an integer array
    */
    vector<int> numIslands2(int n, int m, vector<Point> &operators) {
        // write your code here
        vector<int> res;
        if (n <= 0 || m <= 0 || operators.empty())
            return res;
        vector<int> nums(n*m + 1, 0);//下标表示岛屿位置
        vector<vector<int>> dic{ { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };//方便遍历上下左右四个位置
        int count = 0;
        for (auto c : operators)
        {
            int pos = c.x*m + c.y + 1;
            //若nums[pos]不为0,则岛屿已经出现过,直接返回现有的岛屿数目
            if (nums[pos] > 0)
            {
                res.push_back(count);
                continue;
            }
            //初始化nums[pos]为pos,表示pos最高层的岛屿是本身,此时岛屿数+1
            nums[pos] = pos;
            count++;
            for (auto t : dic)
            {
                int a = c.x + t[0];
                int b = c.y + t[1];
                int tmp = a*m + b + 1;
                if (a < 0 || a >= n || b < 0 || b >= m || nums[tmp] == 0)
                    continue;
                //tmp表示pos的相邻位置,root为tmp的最高层岛屿
                //root!=pos表示pos与root并不属于同一个大岛屿,把pos并入root所在的大岛,
                //nums[pos]=root,并将pos置为root避免重复计算,此时岛屿数目-1
                int root = unionSearch(tmp, nums);
                if (root != pos)
                {
                    nums[pos] = root;
                    pos = root;
                    --count;
                }
            }
            res.push_back(count);
        }
        return res;
    }
    //寻找root的最高层岛屿
    int unionSearch(int root, vector<int> &nums)
    {
        while (root != nums[root])
        {
            nums[root] = nums[nums[root]];
            root = nums[root];
        }
        return root;
    }
};
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值