题目:
一个 n x n 的二维网络 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置。
返回 将这个矩阵变为 “棋盘” 所需的最小移动次数 。如果不存在可行的变换,输出 -1。
“棋盘” 是指任意一格的上下左右四个方向的值均与本身不同的矩阵。
示例 1:
输入: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]
输出: 2
解释:一种可行的变换方式如下,从左到右:
第一次移动交换了第一列和第二列。
第二次移动交换了第二行和第三行。
示例 2:
输入: board = [[0, 1], [1, 0]]
输出: 0
解释: 注意左上角的格值为0时也是合法的棋盘,也是合法的棋盘.
示例 3:
输入: board = [[1, 0], [1, 0]]
输出: -1
解释: 任意的变换都不能使这个输入变为合法的棋盘。
提示:
n == board.length
n == board[i].length
2 <= n <= 30
board[i][j] 将只包含 0或 1
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/transform-to-chessboard
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
判断如果可以变成棋盘, 必要条件为:
有且只能有两个不同行, 两个不同列;
不同的行列必须互补。
计算变换次数: 每次变换可以改变两行的数字, 因为最终棋盘是01相间的排列, 只需要计算行列与01排列不同的数字的数量除以2, 相加即可。
代码:
class Solution {
public:
const int INF = 1e8;
int ones(int a) {
int res = 0;
while(a) res++, a -= (a & -a);
return res;
}
int get(int a, int b) {
if(ones(a) != ones(b)) return INF;
return ones(a^b) / 2;
}
int movesToChessboard(vector<vector<int>>& board) {
set<int> row, col;
int n = board.size();
for(int i=0; i<n; i++) {
int r = 0, c = 0;
for(int j=0; j<n; j++) {
r = r << 1 | board[i][j];
c = c << 1 | board[j][i];
}
row.insert(r), col.insert(c);
}
if(row.size() != 2 || col.size() != 2) return -1;
int r1 = *row.begin(), r2 = *row.rbegin();
int c1 = *col.begin(), c2 = *col.rbegin();
if((r1^r2) != (1<<n)-1 || (c1^c2) != (1<<n)-1) return -1;
int s1 = 0;
for(int i=0; i<n; i+=2) s1 |= 1 << i;
int s2 = ((1<<n)-1) ^ s1;
int r_cost = min(get(r1, s1), get(r1, s2));
int c_cost = min(get(c1, s1), get(c1, s2));
int res = r_cost + c_cost;
if(res >= INF) return -1;
return res;
}
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。