ค้นหาพิกัดของสี่เหลี่ยมทั้งหมดของ 1 ที่ต่อเนื่องกันในอาร์เรย์ 2 มิติใน Javascript

ฉันพบคำถามมากมายที่ถามเกี่ยวกับวิธีการค้นหาสี่เหลี่ยมที่ต่อเนื่องกันที่ใหญ่ที่สุดในอาร์เรย์ 2 มิติ และบางคำถามที่ถามถึงจำนวนสี่เหลี่ยม แต่คำถามเดียวเท่านั้นที่เกี่ยวข้องกับการค้นหาพิกัด ความกว้าง และความสูงของสี่เหลี่ยมทั้งหมดที่จำเป็น ครอบคลุมพื้นที่ 1 วินาทีใน 2D ของ 1 วินาทีและ 0 วินาที

คำถาม (การค้นหาสี่เหลี่ยมในตารางบล็อก 2d) มีวิธีแก้ไข แต่ติดตามได้ยากเนื่องจากอ้างอิงบล็อกโค้ดภายนอก

ฉันกำลังจัดการกับอาร์เรย์ 2 มิติที่ประกอบเป็นพิกเซลของตัวอักษร:

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]]

โดยที่แต่ละอาร์เรย์มีพิกัดมือซ้ายบนและพิกัดมือขวาล่าง (วิธีการใด ๆ ที่ได้รับด้านซ้ายบน ความกว้าง และความสูงก็ใช้ได้เช่นกัน)

ใครสามารถให้ psudocode (หรือ Javascript) สำหรับคำถามที่ถามก่อนหน้านี้หรืออัลกอริทึมอื่นที่ใช้งานได้ หรือให้คำอธิบายเชิงลึกเพิ่มเติมเกี่ยวกับขั้นตอนที่จำเป็น


person Freddie R    schedule 19.02.2019    source แหล่งที่มา


คำตอบ (1)


นี่คือวิธีการดำเนินการโดยใช้อัลกอริธึมง่ายๆ

  1. คำนวณพื้นที่ทั้งหมดที่ปกคลุมด้วยสี่เหลี่ยม -> A
  2. While the area of the rectangles found so far is smaller than A
    1. Find a new rectangle
      1. Find the upper left corner, scan the matrix and stop at the first 1 found
      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;
    }
  }
}

person jo_va    schedule 19.02.2019
comment
สิ่งนี้มีประโยชน์อย่างยิ่ง มันใช้งานได้ (เพิ่มความเร็วประมาณ 10 เท่า) และเข้าใจง่ายกว่าสิ่งอื่นใดที่ฉันเคยเจอมา ขอบคุณ - person Freddie R; 19.02.2019
comment
ฉันใช้รหัสนี้ในไลบรารีจาวาสคริปต์แบบโอเพ่นซอร์ส คุณต้องการให้ได้รับการยอมรับอย่างไร - person Freddie R; 24.02.2019