【Leetcode】711. Number of Distinct Islands II

题目地址:

https://leetcode.com/problems/number-of-distinct-islands-ii/

给定一个 m m m n n n列的 0 − 1 0-1 01矩阵,每个 1 1 1连通块视为一个岛屿。这里的连通是四连通。两个岛屿相同当且仅当其中一个可以通过旋转 0 ° , 9 0 ° , 18 0 ° , 27 0 ° 0^\degree,90^\degree,180^\degree,270^\degree 0°,90°,180°,270°或者镜面翻转后,与另一个岛屿重合。问一共有多少个不同的岛屿。

可以用哈希。这里需要保证两个相同形状的岛屿哈希值一样。我们可以采用这样的哈希方式,设某个岛屿的所有 1 1 1的坐标是 ( a [ i ] x , a [ i ] y ) (a[i]_x,a[i]_y) (a[i]x,a[i]y),其中 0 ≤ i < k 0\le i<k 0i<k,那么令其哈希值为: ∑ i < j ( a [ i ] x − a [ j ] x ) 2 + ( a [ i ] y − a [ j ] y ) 2 \sum_{i<j}\sqrt{(a[i]_x-a[j]_x)^2+(a[i]_y-a[j]_y)^2} i<j(a[i]xa[j]x)2+(a[i]ya[j]y)2 这样显然可以保证相同形状的岛屿哈希值一样。值得注意的是,上面的公式里,如果采用曼哈顿距离,或者去掉根号,得到的哈希值冲突几率较大。这里还是哈希成浮点数,冲突概率很低。但是数岛屿个数的时候,就要比较浮点数了,此时无法用哈希表,而要逐个比较。代码如下:

class Solution {
 public:
  using PII = pair<int, int>;
  int numDistinctIslands2(vector<vector<int>>& g) {
    const double eps = 1e-10;
    int m = g.size(), n = g[0].size();
    vector<double> hashs;
    vector<PII> v;
    for (int i = 0; i < m; i++)
      for (int j = 0; j < n; j++)
        if (g[i][j] == 1) {
          v.clear();
          dfs(i, j, v, g);
          double h = get_hash(v);
          bool found = false;
          for (double x : hashs)
            if (abs(x - h) < eps) {
              found = true;
              break;
            }

          if (!found) hashs.push_back(h);
        }

    return hashs.size();
  }

  double get_hash(vector<PII>& v) {
    double h = 0;
    for (int i = 0; i < v.size(); i++)
      for (int j = i + 1; j < v.size(); j++) {
        auto [x1, y1] = v[i];
        auto [x2, y2] = v[j];
        int dx = x1 - x2, dy = y1 - y2;
        h += sqrt(dx * dx + dy * dy);
      }
    return h;
  }

  void dfs(int x, int y, vector<PII>& v, vector<vector<int>>& g) {
    g[x][y] = 0;
    v.push_back({x, y});
    static int d[] = {-1, 0, 1, 0, -1};
    for (int i = 0; i < 4; i++) {
      int nx = x + d[i], ny = y + d[i + 1];
      if (0 <= nx && nx < g.size() && 0 <= ny && ny < g[0].size() &&
          g[nx][ny] == 1)
        dfs(nx, ny, v, g);
    }
  }
};

时间 O ( m n + ∑ s 2 ) O(mn + \sum s^2) O(mn+s2) s s s为每个岛屿的size,空间 O ( m n ) O(mn) O(mn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值