给你一个 n x n
的二进制网格 grid
,每一次操作中,你可以选择网格的 相邻两行 进行交换。
一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。
请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1 。
主对角线指的是从 (1, 1)
到 (n, n)
的这些格子。
示例 1:
输入:grid = [[0,0,1],[1,1,0],[1,0,0]]
输出:3
示例 2:
输入:grid = [[0,1,1,0],[0,1,1,0],[0,1,1,0],[0,1,1,0]]
输出:-1
解释:所有行都是一样的,交换相邻行无法使网格符合要求。
示例 3:
输入:grid = [[1,0,0],[1,1,0],[1,1,1]]
输出:0
提示:
n == grid.length
n == grid[i].length
1 <= n <= 200
grid[i][j]
要么是 0
要么是 1
。首先我们考虑题意,成功变换之后,对于i行,这一行需要有n-i-1个后缀0,grid[i][i+1]......grid[i][-1]
都为0。对于最后一行,不需要有后缀0。
由于我们只能变换相邻的两行,对于列是改变不了的。那么现存的每一行的后缀0的数量是不会改变的,因此,我们使用一个数组row_zeros,来保存每一行的后缀0数量,当需要交换的时候,只需要交换这个数组中的对应两行的值,而不需要交换grid,大大减少了时间复杂度。也就是说,在遍历完grid,计算出row_zeros之后,我们就不需要grid了。
下面我们考虑如何计算。因为越上面的行,对后缀0的要求越高,所以我们从i=0行开始往下遍历,直到倒数第二行(因为最后一行不需要)。遍历的过程中,可能出现几种情况:
遍历完所有行,返回计数的res。
class Solution:
def minSwaps(self, grid: List[List[int]]) -> int:
res = 0
n = len(grid)
# row_zeros[i]表示i行的后缀0个数
row_zeros = [0] * n
# 遍历,填写row_zeros
for i in range(n):
for j in range(n-1,-1,-1):
if grid[i][j] == 0:
row_zeros[i] += 1
else:
break
# 从第一行开始遍历,到倒数第二行
for i in range(n-1):
# 如果该行的后缀0满足要求,pass
if row_zeros[i] >= n-i-1:
pass
# 不符合要求,从下一行开始,找到第一个满足条件的
else:
for j in range(i+1,n):
if row_zeros[j] >= n-i-1:
break
# 找到这一行,将符合条件这个一次一次往上面互换,换到i行
# 互换的时候,只需要互换row_zeros对应的值即可,不需要互换grid
if row_zeros[j] >= n-i-1:
for k in range(j,i,-1):
row_zeros[k],row_zeros[k-1] = row_zeros[k-1],row_zeros[k]
res += 1
# 如果没找到,说明不存在符合的i行的行,返回-1
else:
return -1
# 最后返回res
return res
class Solution {
public:
int minSwaps(vector<vector<int>>& grid) {
int res = 0;
int n = grid.size();
// row_zeros[i]表示i行的后缀0个数
vector<int> row_zeros(n,0);
// 遍历,填写row_zeros
for (int i = 0; i < n; ++i)
for (int j = n-1;j > -1;--j){
if (grid[i][j] == 0)
row_zeros[i] += 1;
else break;
}
// 从第一行开始遍历,到倒数第二行
for (int i = 0; i < n-1; ++i){
// 如果该行的后缀0满足要求,pass
if (row_zeros[i] >= n-i-1) continue;
// 不符合要求,从下一行开始,找到第一个满足条件的
else{
int j = i+1;
for (;j < n-1; ++j){
if (row_zeros[j] >= n-i-1){
break;
}
}
// 找到这一行,将符合条件这个一次一次往上面互换,换到i行
// 互换的时候,只需要互换row_zeros对应的值即可,不需要互换grid
if (row_zeros[j] >= n-i-1){
for (int k = j; k > i; --k){
swap(row_zeros[k],row_zeros[k-1]);
res ++;
}
}
// 如果没找到,说明不存在符合的i行的行,返回-1
else return -1;
}
}
// 最后返回res
return res;
}
};