leetcode 5477. 排布二进制网格的最少交换次数 冒泡排序 思维题 暴力

  1. 排布二进制网格的最少交换次数

给你一个 n x n 的二进制网格 grid,每一次操作中,你可以选择网格的 相邻两行 进行交换。

一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。

请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1 。

主对角线指的是从 (1, 1) 到 (n, n) 的这些格子。
leetcode 5477. 排布二进制网格的最少交换次数 冒泡排序 思维题 暴力_第1张图片

输入:grid = [[0,0,1],[1,1,0],[1,0,0]]
输出:3

leetcode 5477. 排布二进制网格的最少交换次数 冒泡排序 思维题 暴力_第2张图片
leetcode 5477. 排布二进制网格的最少交换次数 冒泡排序 思维题 暴力_第3张图片

思路 :

  • 先观察排好的结果有什么性质

    • 如图 leetcode 5477. 排布二进制网格的最少交换次数 冒泡排序 思维题 暴力_第4张图片
  • 对于每个原始矩阵我们可以计算出一个数组,如图

  • leetcode 5477. 排布二进制网格的最少交换次数 冒泡排序 思维题 暴力_第5张图片

  • 再用原数组和交换好的标准数组比对

  • 当第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

你可能感兴趣的:(leetcode,冒泡排序,思维题,暴力)