[LeetCode] Transform to Chessboard 转为棋盘
An N x N board contains only 0s and 1s. In each move, you can swap any 2 rows with each other, or any 2 columns with each other.
What is the minimum number of moves to transform the board into a "chessboard" - a board where no 0s and no 1s are 4-directionally adjacent? If the task is impossible, return -1.
Examples:
Input: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]
Output: 2
Explanation:
One potential sequence of moves is shown below, from left to right: 0110 1010 1010
0110 --> 1010 --> 0101
1001 0101 1010
1001 0101 0101 The first move swaps the first and second column.
The second move swaps the second and third row. Input: board = [[0, 1], [1, 0]]
Output: 0
Explanation:
Also note that the board with 0 in the top left corner,
01
10 is also a valid chessboard. Input: board = [[1, 0], [1, 0]]
Output: -1
Explanation:
No matter what sequence of moves you make, you cannot end with a valid chessboard.
Note:
boardwill have the same number of rows and columns, a number in the range[2, 30].board[i][j]will be only0s or1s.
这道题给了我们一个二维数组,里面都是由0和1组成的,让我们通过交换行或者列来形成一个棋盘。棋盘我们都见过吧,就是国际象棋的那种棋盘,黑白相间的那种,用数组表示就是0和1交替出现,相邻位置上的数字必定不是一样的。这道题默认的棋盘的起始位置可以是1或者0,然后依次类推可得到所有位置上的值。这道题最大的难点是在于判断给定的数组最终能否组成棋盘,因为能通过交换组成棋盘的数组其实是有很多苛刻条件需要满足的,只有这些条件都满足了,才能到计算交换数到那一步。首先我们先来看长度为4的棋盘:
1 0 1 0
0 1 0 1
1 0 1 0
0 1 0 1
或者:
0 1 0 1
1 0 1 0
0 1 0 1
1 0 1 0
我们发现对于长度为偶数的棋盘,每一行0和1的个数都是相等的,不管我们如何交换行和列,0和1的个数都是不会变化的,再看看长度为奇数的棋盘,比如3:
1 0 1
0 1 0
1 0 1
或者:
0 1 0
1 0 1
0 1 0
我们发现对于长度为奇数的棋盘,各行的0和1个数不同,但是还是有规律的,每行的1的个数要么为 n/2,要么为 (n+1)/2,这个规律一定要保证,不然无法形成棋盘。
还有一个很重要的规律,我们观察题目给的第一个例子,如果我们只看行,我们发现只有两种情况 0110 和 1001,如果只看列,只有 0011 和 1100,我们发现不管棋盘有多长,都只有两种情况,而这两种情况上各位上是相反的,只有这样的矩阵才有可能转换为棋盘。那么这个规律可以衍生出一个规律,就是任意一个矩形的四个顶点只有三种情况,要么四个0,要么四个1,要么两个0两个1,不会有其他的情况。那么四个顶点亦或在一起一定是0,所以我们判断只要亦或出了1,一定是不对的,直接返回-1。之后我们来统计首行和首列中的1个数,因为我们要让其满足之前提到的规律。统计完了首行首列1的个数,我们判断如果其小于 n/2 或者大于 (n+1) / 2,那么一定无法转为棋盘。我们还需要算下首行和首列跟棋盘位置的错位的个数,虽然 01010 和 10101 都可以是正确的棋盘,我们先默认跟 10101 比较好了,之后再做优化处理。
最后的难点就是计算最小的交换步数了,这里要分n的奇偶来讨论。如果n是奇数,我们必须得到偶数个,为啥呢,因为我们之前统计的是跟棋盘位置的错位的个数,而每次交换行或者列,会修改两个错位,所以如果是奇数就无法还原为棋盘。举个例子,比如首行是 10001,如果我们跟棋盘 10101 比较,只有一个错位,但是我们是无法通过交换得到 10101的,所以我们必须要交换得到 01010,此时的错位是4个,而我们通过 n - rowDiff 正好也能得到4,这就是为啥我们需要偶数个错位。如果n是偶数,那么就不会出现这种问题,但是会出现另一个问题,比如我们是 0101,这本身就是正确的棋盘排列了,但是由于我们默认是跟 1010 比较,那么我们会得到4个错位,所以我们应该跟 n - rowDiff 比较取较小值。列的处理跟行的处理完全一样。最终我们把行错位个数跟列错位个数相加,再除以2,就可以得到最小的交换次数了,之前说过了每交换一次,可以修复两个错位,参见代码如下:
class Solution {
public:
int movesToChessboard(vector<vector<int>>& board) {
int n = board.size(), rowSum = , colSum = , rowDiff = , colDiff = ;
for (int i = ; i < n; ++i) {
for (int j = ; j < n; ++j) {
if (board[][] ^ board[i][] ^ board[][j] ^ board[i][j]) return -;
}
}
for (int i = ; i < n; ++i) {
rowSum += board[][i];
colSum += board[i][];
rowDiff += (board[i][] == i % );
colDiff += (board[][i] == i % );
}
if (n / > rowSum || rowSum > (n + ) / ) return -;
if (n / > colSum || colSum > (n + ) / ) return -;
if (n % ) {
if (rowDiff % ) rowDiff = n - rowDiff;
if (colDiff % ) colDiff = n - colDiff;
} else {
rowDiff = min(n - rowDiff, rowDiff);
colDiff = min(n - colDiff, colDiff);
}
return (rowDiff + colDiff) / ;
}
};
参考资料:
https://leetcode.com/problems/transform-to-chessboard/
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Transform to Chessboard 转为棋盘的更多相关文章
- [Swift]LeetCode782. 变为棋盘 | Transform to Chessboard
An N x N board contains only 0s and 1s. In each move, you can swap any 2 rows with each other, or an ...
- 782. Transform to Chessboard
An N x N board contains only 0s and 1s. In each move, you can swap any 2 rows with each other, or an ...
- [LeetCode] To Lower Case 转为小写
Implement function ToLowerCase() that has a string parameter str, and returns the same string in low ...
- UVA 11214 Guarding the Chessboard 守卫棋盘(迭代加深+剪枝)
暴力,和八皇后很像,用表示i+j和i-j标记主对角线,但是还是要加一些的剪枝的. 1.最裸的暴搜 6.420s,差点超时 2.之前位置放过的就没必要在放了,每次从上一次放的位置开始放 0.400s # ...
- Swift LeetCode 目录 | Catalog
请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift 说明:题目中含有$符号则为付费题目. 如 ...
- [LeetCode] Gas Station 加油站问题
There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. You ...
- LeetCode All in One题解汇总(持续更新中...)
突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...
- leetcode 学习心得 (4)
645. Set Mismatch The set S originally contains numbers from 1 to n. But unfortunately, due to the d ...
- All LeetCode Questions List 题目汇总
All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...
随机推荐
- https://www.chromestatus.com/features/5093566007214080
移动端滑动报错:Unable to preventDefault inside passive event listener due to target being treated as passiv ...
- 适配器模式-Adapter(Java实现)
适配器模式-Adapter 是作为两个不兼容的接口之间的桥梁. 本篇文章的代码github地址: https://github.com/GoldArowana/design-patterns/tree ...
- javaScript drag对象进行拖拽使用详解
目录 drag简介 兼容性 drag事件 拖拽流程 DataTransfer对象 drag拖放桌面文件 drag实例 小结 drag简介 HMTL5提供的支持原生拖拽的实现 兼容性如何? 桌面端的支持 ...
- [物理学与PDEs]第4章习题3 一维理想反应流体力学方程组的数学结构
证明: Euler 坐标系下的一维反应流体力学方程组 (3. 10)-(3. 13) 也是一个一阶拟线性双曲型方程组. 证明: 由 (3. 10), (3. 12), (3. 13) 知 $$\bex ...
- [物理学与PDEs]第4章第2节 反应流体力学方程组 2.4 反应流体力学方程组的数学结构
1. 粘性热传导反应流体力学方程组是拟线性对称双曲 - 抛物耦合组. 2. 理想反应流体力学方程组是一阶拟线性对称双曲组 (取 ${\bf u},p,S,Z$ 为未知函数). 3. 右端项具有间 ...
- [物理学与PDEs]第1章习题4 偶极子的极限电势
对在 $P_0$ 及 $P_1$ 处分别置放 $-q$ 及 $+q$ 的点电荷所形成的电偶极子, 其偶极距 ${\bf m}=q{\bf l}$, ${\bf l}=\vec{P_0P_1}$. 试证 ...
- BIO 和 NIO
一.阻塞(Block)和非阻塞(NonBlock) 阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,当数据没有准备的时候阻塞: 阻塞:往往需要等待缞冲区中的数据准备好过后才处理其他 ...
- Django之Xadmin
零.预备知识 单例对象 方式一:__new__方法 方式二:模块导入,只要在引入的文件中实例了这个对象,不管引道哪里,这个对象都指向同一个内存空间 class My_singleton(object) ...
- SQL Server - AS
AS 是给现有的字段名/表名指定一个别名的意思.
- 肺结节CT影像特征提取(二)——肺结节CT图像特征提取算法描述
摘自本人毕业论文<肺结节CT影像特征提取算法研究> 医学图像特征提取可以认为是基于图像内容提取必要特征,医学图像中需要什么特征基于研究需要,提取合适的特征.相对来说,医学图像特征提取要求更 ...