每日一题,手撕代码不是梦,我认真的过每一分钟....... Stop! 开始正文
问题分析
一个 n x n 的二维网络 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置。返回将这个矩阵变为 “棋盘” 所需的最小移动次数 。如果不存在可行的变换,输出 -1。
1)由于交换行(列)时不会改变列(行)元素的对应关系,所以先交换行还是列对最终结果没有影响,最小移动次数可以由交换行/列的最小移动次数之和得到。
2)先判断能否进行交换,能够交换成功的矩阵应该满足下述条件:
a. 行序列的种类只能有两种,且要互补,才能将其上下调至互补状态,例如[‘0110’, '1001'];
b. 每个行/列序列内部0和1的个数要对半,才能将其左右调至互补状态,例如示例中各两个;
3)不能进行交换,直接返回-1:
4)能够进行交换,再分别计算交换行/列的最小移动次数(只需计算1行1列即可):
a. 以第一行为例,左右互不相同的理想状态会有两种:['0101', '1010'],因此['0110']与理想状态相差的位数分别为[2,2],可以发现两者距离和总是为n,所以min(d1,d2) = min(d1,n-d1);
b. 列的计算与行同理,最后最小移动次数由最小不同位数整除2得到。
一、先决条件
先排除board输出为0或-1的情况,代码如下:
# 边界条件1
n = len(board)
if n <=1: return 0
# 边界条件2
rows = ["".join(str(c) for c in r) for r in board] # 返回每一行的字符串形式
counter = collections.Counter(rows) # 输出每种行序列的次数 {'0110':2, '1010':2}
keys = list(Counter) # 输出行序列的种类 ['0110', '1010']
if len(keys) != 2 or abs(counter[keys[0]] - counter[keys[1]]) > 1 or abs(keys[0].count('0') - keys[0].count('1'))>1 or any(a==b for a,b in zip(*keys)):
return -1
二、计算最小交换次数(由最小不同位数得到)
## 计算行和列的不同位数(理想状态取010101......)
rowdiff = sum(board[0][i] != (i%2) for i in range(n))
coldiff = sum(board[i][0] != (i%2) for i in range(n))
## 计算行和列的最小不同位数(比较两种理想状态)
rowdiff = n-rowdiff if rowdiff%2!=0 or (n%2==0 and n-rowdiff<rowdiff) else rowdiff
coldiff = n-coldiff if coldiff%2!=0 or (n%2==0 and n-coldiff<rowdiff) else coldiff
return (rowdiff+coldiff)//2
总结
以上就是今天要讲的内容,第一次写博客请大家多多包涵。在这里也要感谢力扣用户Justin Yuan提供的代码和讲解~