[Leetcode] 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 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:

  • board will have the same number of rows and columns, a number in the range [2, 30].
  • board[i][j] will be only 0s or 1s.

思路

通过观察,我们发现一个合法的棋盘必须具备如下两个条件:

1)只能有且仅有两种行类型,例如如果一种行类型为01010011,那么另外一种行类型只能为01010011或者10101100;该限制条件同样适合于列类型。此外,任何棋盘内部的四边形,要么四个角都是1,要么四个角都是0,要么两个0和两个1。

2)每一行和每一列中,0和1的数量都是相等的,假设棋盘是N * N大小的,那么:a)如果N = 2 * K,那么每一行每一列有且仅有K个0和K个1;b)如果N = 2 * K + 1,那么每一行每一列要么有K个1和K+1个0,要么有K+1个1和K个0。

由于每次的行交换和列交换都不破坏上述性质,所以以上两个条件就成了判断是否可以形成合法棋盘的充要条件。一旦我们判断出来某个棋盘是合法的,我们就开始计算最小的交换次数。基于上述性质,我们对第一行进行整理(通过交换列来实现),以N = 5为例来说明:

1)如果N是偶数,我们计算实现01010和10101需要的最小移动步数,并且取最小者;

2)如果N是奇数,我们就只有一种取法,所以就取移动步数为偶数的最小次数。

总之,我感觉这道题目还是挺难的,而且对数学要求很高。希望大家好运,在面试的时候不要遇到这种题目。。。

代码

class Solution {
public:
    int movesToChessboard(vector<vector<int>>& board) {
        int N = board.size(), rowSum = 0, colSum = 0, rowSwap = 0, colSwap = 0;
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (board[0][0] ^ board[i][0] ^ board[0][j] ^ board[i][j]) {
                    return -1;
                }
            }
        }
        for (int i = 0; i < N; ++i) {
            rowSum += board[0][i];
            colSum += board[i][0];
            rowSwap += board[i][0] == i % 2;
            colSwap += board[0][i] == i % 2;
        }
        if (N / 2 > rowSum || rowSum > (N + 1) / 2) {
            return -1;
        }
        if (N / 2 > colSum || colSum > (N + 1) / 2) {
            return -1;
        }
        if (N % 2) {
            if (colSwap % 2) {
                colSwap = N - colSwap;
            }
            if (rowSwap % 2) {
                rowSwap = N - rowSwap;
            }
        }
        else {
            colSwap = min(N - colSwap, colSwap);
            rowSwap = min(N - rowSwap, rowSwap);
        }
        return (colSwap + rowSwap) / 2;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值