1536. Minimum Swaps to Arrange a Binary Grid

練習日期:2026-03-02

難度:Medium

類型:Array、Greedy、Matrix

📘 題目敘述

給你一個 n x n 的二元矩陣 grid,一次操作中你可以選擇 grid 的兩個相鄰列(rows)並交換它們。

如果一個矩陣滿足:主對角線(main diagonal)上方的所有格子都是 0,則稱這個矩陣是 valid。

請回傳把 grid 變成 valid 所需的最少操作次數;如果不可能變成 valid,回傳 -1

主對角線是從格子 (1, 1)(n, n) 的那條對角線。

條件限制

  • n == grid.length == grid[i].length
  • 1 <= n <= 200
  • grid[i][j] 只會是 01

🧠 解題思路

這題的條件「主對角線上方全是 0」可以換成每一列的限制來看:

i 列(0-index)在對角線上方的位置是 j > i。所以第 i 列必須滿足:在 j = i+1n-1 這段都要是 0。

換句話說:

i 列的尾端至少要有 n - i - 1 個連續的 0。

所以我先把每一列尾端連續 0 的數量算出來,存成一個陣列 v

接著從上到下依序安排每一列:

  • i 列需要 v[j] >= n - i - 1
  • 我在剩下的列裡從上往下找第一個符合的列(最靠前的)
  • 找到後把它「搬到」目前位置,搬動需要的相鄰交換次數就是它距離目前位置的步數
  • 我用 ans += j 來累積這個搬動成本(因為我直接把那一列從 v 刪掉,等於把它提到最前面)
  • 如果找不到任何列符合,就代表不可能,回傳 -1

這就是一個典型的 greedy:每一層都選「最靠前」能滿足需求的列,因為這樣交換次數最少。

所有變數

  • n:矩陣大小(列數 / 行數)。
  • vv[r] 代表第 r 列尾端連續 0 的數量。
  • ans:累積的最少相鄰列交換次數。
  • count:在計算某一列尾端 0 時的計數器。
  • check:用來判斷第 i 個位置是否找得到可用的列(找不到就回傳 -1)。

🪜 主要流程步驟

1. 先把每一列「尾端連續 0 的數量」算出來放進 v

我對每一列從最右邊開始往左掃:

  • 只要遇到 0 就 count++
  • 一旦遇到 1 就停止

最後把 count 放進 v。這一步完成後,v 就代表每列的「可用程度」。


2. 從上到下依序決定第 i 列要放哪一列

對於位置 i,它需要的尾端 0 數量是:need = n - i - 1

我在目前剩下的 v 裡從前往後找第一個 v[j] >= need 的列。


3. 找到就把它搬上來,ans 加上搬動距離,並從 v 移除

假設我找到的是第 j 個:

把它搬到目前的位置需要做 j 次相鄰交換(往上推 j 格)。

所以我做:

  • ans += j
  • v.erase(v.begin() + j)

這個 erase 的效果等於把那列抽出來放到前面(已經固定到第 i 列),剩下的列相對順序不變。


4. 如果某個 i 找不到任何符合的列,就回傳 -1

如果整個 v 掃完都沒有 v[j] >= need,代表無論怎麼交換都無法讓第 i 列達成條件,直接回傳 -1


5. 全部位置都安排完成後回傳 ans

如果 i = 0..n-1 都能找到列,代表一定能組成 valid grid,回傳累積的 ans

⏱️ 複雜度

  • 時間複雜度:O(n^2)。先算 vO(n^2)(每列最多掃 n 次),後面安排每一列也可能掃 v,再加上 erase 的位移成本,整體在 n <= 200 下可接受。
  • 空間複雜度:O(n),主要是 v 陣列。

💻 程式碼實作

class Solution {
public:
    int minSwaps(vector<vector<int>>& grid) {
        int n = grid.size();
        vector<int> v;
        for (auto& row : grid) {
            int count = 0;
            for (int j = n - 1; j >= 0; j--) {
                if (row[j] == 0) {
                    count++;
                } else {
                    break;
                }
            }
            v.push_back(count);
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            bool check = true;
            for (int j = 0; j < v.size(); j++) {
                if (v[j] >= n - i - 1) {
                    check = false;
                    ans += j;
                    v.erase(v.begin() + j);
                    break;
                }
            }
            if (check) {
                return -1;
            }
        }
        return ans;
    }
};

https://leetcode.com/problems/minimum-swaps-to-arrange-a-binary-grid/

作者: scottnick
撰寫日期: 2026-03-02
類別:
原文連結: https://scottnick.github.io/cpp-notes/all%20problems/1536-minimum-swaps-to-arrange-a-binary-grid.html