【问题标题】:Find the coordinates of all rectangles of contiguous 1s in a 2D array in Javascript在Javascript中查找二维数组中所有连续1的矩形的坐标
【发布时间】:2019-07-12 10:03:52
【问题描述】:

我发现了许多问题,询问如何在二维数组中找到最大的连续矩形,还有一些问题询问矩形的数量,但只有一个问题涉及查找所有数组的坐标、宽度和高度在 1 和 0 的 2D 中覆盖 1 区域所需的矩形。

问题 (Finding rectangles in a 2d block grid) 有一个解决方案,但由于它引用了一个外部代码块,所以很难理解。

我正在处理构成字母像素的二维数组:

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0

0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0

此处所需的输出类似于:

[[4,0,6,17],[7,0,16,2],[7,7,15,9],[7,15,15,17]]

每个数组都包含左上角坐标和右下角坐标(任何获取左上角和宽度和高度的方法也可以)。

有人可以为之前提出的问题或其他有效算法提供伪代码(或 Javascript),或者提供对所需步骤的更深入解释吗?

【问题讨论】:

    标签: javascript arrays multidimensional-array


    【解决方案1】:

    这是一种使用简单算法的方法。

    1. 计算矩形覆盖的总面积 -> A
    2. 虽然到目前为止找到的矩形面积小于 A
      1. 找到一个新的矩形
        1. 找到左上角,扫描矩阵并停在找到的第一个 1
        2. 找到右下角,从左上角开始,扫描矩阵,在找到的第一个0处停止
      2. 通过将每个单元格设置为 1 以外的值来标记找到的矩形
      3. 将其面积添加到累计面积中
      4. 将矩形推到列表中

    const mat = [
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0],//0
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0],//1
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0],//2
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//3
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//4
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//5
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//6
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],//7
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],//8
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],//9
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//10
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//11
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//12
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//13
      [0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],//14
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0],//15
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0],//16
      [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0] //17
    ];
    
    const W = mat[0].length;
    const H = mat.length;
    
    // get the area covered by rectangles
    let totalRectArea = 0;
    for (let i = 0; i < W; ++i) {
      for (let j = 0; j < H; ++j) {
        totalRectArea += mat[j][i] > 0 ? 1 : 0;
      }
    }
    
    const rects = [];
    let rectArea = 0;
    
    // find all rectangle until their area matches the total
    while (rectArea < totalRectArea) {
      const rect = findNextRect();
      rects.push(rect);
      markRect(rect);
      rectArea += (rect.x2 - rect.x1 + 1) * (rect.y2 - rect.y1 + 1);
    }
    
    console.log(rects);
    
    function findNextRect() {
      // find top left corner
      let foundCorner = false;
      const rect = { x1: 0, x2: W-1, y1: 0, y2: H-1 };
      for (let i = 0; i < W; ++i) {
        for (let j = 0; j < H; ++j) {
          if (mat[j][i] === 1) {
            rect.x1 = i;
            rect.y1 = j;
            foundCorner = true;
            break;
          }
        }
        if (foundCorner) break;
      }
      // find bottom right corner
      for (let i = rect.x1; i <= rect.x2; ++i) {
        if (mat[rect.y1][i] !== 1) {
          rect.x2 = i-1;
          return rect;
        }
        for (let j = rect.y1; j <= rect.y2; ++j) {
          if (mat[j][i] !== 1) {
            rect.y2 = j-1;
            break;
          }
        }
      }
      return rect;
    }
    
    // mark rectangle so won't be counted again
    function markRect({ x1, y1, x2, y2 }) {
      for (let i = x1; i <= x2; ++i) {
        for (let j = y1; j <= y2; ++j) {
          mat[j][i] = 2;
        }
      }
    }

    【讨论】:

    • 这非常有帮助。它有效(速度提高了约 10 倍),并且比我遇到的任何其他东西都更容易理解,谢谢。
    • 我在一个开源的 javascript 库中使用这段代码,你希望如何得到认可?
    猜你喜欢
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-17
    • 1970-01-01
    • 2015-11-07
    • 1970-01-01
    相关资源
    最近更新 更多