其他分享
首页 > 其他分享> > LeetCode/变为棋盘

LeetCode/变为棋盘

作者:互联网

一个 n x n 的二维网络 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置
返回将这个矩阵变为  “棋盘”  所需的最小移动次数 ,如果不存在可行的变换,输出 -1

1. 数学方法

移动使满足条件的题目,首先得判断棋盘是否满足条件
容易从棋盘得知,需要满足以下几个条件

  1. 棋盘只存在两种行(列),即矩阵秩为2
  2. 对应的两种行(列)每个元素相异,即两行(列)正交
  3. 对于任意一行(列),0和1的个数差不超过1

判断思路:将所有行和列与第一行、第一列比较,判断是否满足相同或相异
计算判断第一行和第一列0和1的个数差值即可(满足条件的话,其它相同或相异的也必然满足)

移动次数计算:假定一种顺序,计算不在位的个数,分奇偶进行处理即可

class Solution {
public:
    int movesToChessboard(vector<vector<int>>& board) {
        int n = board.size(), rowSum = 0, colSum = 0, rowDiff = 0, colDiff = 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;
        }
        //判断行和列不在位的个数,同时求和用于判断是否符合要求(0和1个数相差不超过一)
        for (int i = 0; i < n; ++i) {//先假设正确顺序为(101010....)
            rowSum += board[0][i];
            colSum += board[i][0];
            rowDiff += (board[i][0] == i % 2);
            colDiff += (board[0][i] == i % 2);
        }
        //如果第一行1的个数少于一半或多于一半(奇偶)
        if (n / 2 > rowSum || rowSum > (n + 1) / 2) return -1;
        //如果第一列1的个数少于一半或多于一半(奇偶)
        if (n / 2 > colSum || colSum > (n + 1) / 2) return -1;
        
        if (n % 2) {//如果为奇数(01010->10101无法进行转化,只能转化为01010)
            if (rowDiff % 2) rowDiff = n - rowDiff;//不在位为奇数,转化为偶数
            if (colDiff % 2) colDiff = n - colDiff;//不在位为奇数,转化为偶数
        } else {//如果为偶数
            rowDiff = min(n - rowDiff, rowDiff);//计算第一行最小不在位
            colDiff = min(n - colDiff, colDiff);//计算第一列最小不在位
        }
        return (rowDiff + colDiff) / 2;//移动一次可以解决两个不在位
    }
};

标签:rowDiff,int,个数,变为,board,第一列,棋盘,colDiff,LeetCode
来源: https://www.cnblogs.com/929code/p/16614878.html