给你一个 n x n 的二进制网格 grid,每一次操作中,你可以选择网格的 相邻两行 进行交换。
一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。
请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1 。
主对角线指的是从 (1, 1) 到 (n, n) 的这些格子。
输入:grid = [[0,0,1],[1,1,0],[1,0,0]]
输出:3
思路 :
先观察排好的结果有什么性质
对于每个原始矩阵我们可以计算出一个数组,如图
再用原数组和交换好的标准数组比对
当第arr[i]
小于标准矩阵第i
行需要的连续0
个数时,应该发生交换
标准矩阵i 行至少要 |
4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|
当前矩阵数组为(2号位置不合格) | 4 | 0 |
2 | 1 | 3 |
向后找最近的合格值(即arr[5]=3 ) |
4 | 0 |
2 | 3 |
1 |
4 | 0 |
3 |
2 | 1 | |
4 | 3 |
0 |
2 | 1 | |
这样我们就完成了一次行最小
移动,3
移动到0
位置发生了3
次交换,把第j
行换到第i
行需要j-i
次交换
于是代码就好写了,
i
合适就不动arr[i]
小于需要的连续0
,就和后面最近
的满足要求的
值交换#define debug
#ifdef debug
#include
#include "/home/majiao/mb.h"
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXN ((int)1e5+7)
#define ll long long int
#define QAQ (0)
using namespace std;
#define num(x) (x-'0')
#define show(x...) \
do { \
cout << "\033[31;1m " << #x << " -> "; \
err(x); \
} while (0)
void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }
int a[512];
class Solution {
public:
int minSwaps(vector<vector<int>>& mtx) {
memset(a, false, sizeof(a));
int n = mtx.size();
for(int i=0; i<n; i++) { //生成arr[数组]
int cnt = 0;
for(int j=n-1; j>=0; j--) { //统计从右往左的连续 0
if(mtx[i][j] == 0) cnt ++;
else break;
}
a[i+1] = cnt;
}
int ans = 0;
for(int i=1, k=n-1; i<=n; i++, k--) { //对于每个值和标准数组比较
if(a[i] < k) { //当前行连续 0 个数小于标准行,就要发生交换
for(int j=i+1; j<=n; j++) { //向后找第一个大于等于当前标准行的值j,
if(a[j] >= k) {
int now = j;
while(now > i) { //把 j 行向上冒泡
swap(a[now], a[now-1]);
now --;
ans ++;
}
break;
}
}
}
if(a[i] < k) return -1; //无法完成交换 返回-1
}
return ans;
}
};
#ifdef debug
signed main() {
freopen("test", "r", stdin);
clock_t stime = clock();
Solution s;
vector<vector<int> > mtx = {
{0,0,1},
{1,1,0},
{1,0,0}
};
cout << s.minSwaps(mtx) << endl;
clock_t etime = clock();
printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
return 0;
}
#endif