[每日一题] leetcode782.变为棋盘

125 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

782. 变为棋盘

一个 n×nn \times n 的二维网络 board board 仅由 00 和 11 组成 。
每次移动,你能任意交换两列或是两行的位置。
返回 将这个矩阵变为  “棋盘”  所需的最小移动次数 。如果不存在可行的变换,输出 -1。
“棋盘” 是指任意一格的上下左右四个方向的值均与本身不同的矩阵。

示例1

image.png

输入: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]
输出: 2
解释:一种可行的变换方式如下,从左到右:
第一次移动交换了第一列和第二列。
第二次移动交换了第二行和第三行。
示例2

image.png

输入: board = [[0, 1], [1, 0]]
输出: 0
解释: 注意左上角的格值为0时也是合法的棋盘,也是合法的棋盘.
数据范围
  • n == board.length
  • n == board[i].length
  • 2 <= n <= 30
  • board[i][j] 将只包含 0或 1
思路

要使得任意一格的上下左右四个方向的值均与本身不同的矩阵。 则对于自上而下每一个格子,它的下方和右方一定和自己不一样。
则最后的情况一定对应着这种情况:
1 0 1 0 1 0 1 0 ....
0 1 0 1 0 1 0 1 ....
1 0 1 0 1 0 1 0 ....
(从0 或 1 行开始)
那么,仔细观察一下,相邻两行想与一定为0,且只会出现两种类型的行
存在任意次交换两列之后,并不会改变行与行之间的关系
那么,抛开行不谈,我们的列是不是一样呢?
显然,也是一样的。所以我们可以先 “还原” 行的排列
再“还原”列的排列
下一个问题: 对于一行只包含a和b的序列 如何排列才能达到排列次数最少?
这个时候把奇数和偶数分开考虑
若是偶数,那么ababab或者bababa都是一样的,所以,取最小的即可
若是奇数,那么这个时候出现多1个的数一定排在偶数位置(从0开始)
分类讨论即可

代码
class Solution {
public:
    int movesToChessboard(vector<vector<int>>& board) {
        vector<int> ve(board.size());
        map<int, int> mp;
        for (int i = 0; i < board.size(); i ++) {
            int res = 0;
            for (auto v : board[i]) 
                res = (res << 1) + v;
            mp[res] ++;
            ve[i] = res;
            if (mp.size() > 2) return -1;
        }
        
        auto t = mp.begin();
        auto a = *t;
        auto b = *(++ t);
        if (abs(a.second - b.second) > 1 || (a.first & b.first)) return -1;
        int ans = 0, odd = 0, even = 0, n = board.size();

        int f = 0;
        if (a.second < b.second) f = 1;
        for (int i = 0; i < n; i ++) 
            if (ve[i] == a.first && i % 2 != f) odd ++;
        if (n % 2 == 0) ans = min(a.second - odd, odd);
        else ans = odd;

        int x = a.first, cnt = 0;
        int len = board.back().size();
        odd = 0, even = 0;
        for (int i = 0, j = len -1; i < len; j --, i ++) {
            if (x >> j & 1) {
                cnt ++;
                if (i % 2) odd ++;
                else even ++;
            }
        }
        if (len % 2 == 0) ans += min(odd, cnt - odd);
        else {
            if (cnt > len - cnt) ans += odd;
            else ans += even;
        }

        if (abs(cnt - (len - cnt)) > 1) return -1;
        return ans;
    }
};