力扣LeetCode: Python3解法 - 782.变为棋盘

每日一题,手撕代码不是梦,我认真的过每一分钟....... 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提供的代码和讲解~

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值