【Leetcode】782. Transform to Chessboard 变为棋盘

12

解法

参考:https://blog.csdn.net/u014688145/article/details/79312830
https://blog.csdn.net/magicbean2/article/details/79722329

这道题需要利用特殊性来加快速度,首先根据题目要求我们可以很容易了解到最后转换的结果是什么样子的,因为只要把[0][0]设置为0或者1,后面的位置的值都可以推理得到,这对于我们过滤掉一些肯定不能交换得到的矩阵是很有帮助的:

  1. 首先很明显,当n为偶数时,每一行、列的0和1个数相等;当n为奇数时,每一行、列的0和1个数相差1。

  2. 其次每一行(列)的初始排布只可能完全相同或完全相反,也就是说整个矩阵只可能有两种初始排布。并且这两种排布的数量要么相等要么相差1。

    “两个行类型”+“数量相等或相差1”
    “两个行类型”+“两个列类型”
    是一样的效果

    这是因为,如果行(列)完全相同,那么,交换列(行)的时候就对相同的行做了相同的操作,这些相同的行摆在不相邻的位置即可;如果行(列)完全相反,那么交换列(行)的时候刚好就能换出相反的行,相反的行把相同的行隔开就可以了。举个例子,假如:

    0011
    0110
    

    那么我们把第一行交换得满足条件时:

    0101
    0110
    # 或者
    1010
    1100
    

    必然有两列里相邻的两行相同了(0、1或者0、3),假如我们通过行交换用其它行把这两行隔开,那么对于相邻行不相同的那两列(2、3或1、2),它们必然会与隔开它们的那一行的值相同。

通过以上两点判断这个矩阵能否通过交换得到之后,怎么找最小交换次数呢?

首先我们知道,只要把首行通过交换列交换成功,那么后面就不需要再进行列交换了,然后把首列通过行交换成功,就是最小交换次数了。行交换和列交换是互不冲突的,分别取最小次数即可。

当n为奇数时,首列的最终状态是确定的,假如是0多,那么一定是以0开头;我们可以统计最终状态和当前状态相差的位数,每一次交换一定会消除两个不同的地方,那么交换次数就是diff//2

因为交换的两列一定不同,否则相当于没交换,假如交换前是一列对应一列不对应,交换过来的那列一定又会使对应的列变得不对应,所以不可能消除;假如交换前是两个都不对应,那么交换后一定两个都对应。

当n为偶数时,由0开头还是由1开头都可以,我们假设由0开头算出来diff,那么由1开头的不对应数为n-diff,取两者之间的最小值就好。

class Solution(object):
    def movesToChessboard(self, board):
        """
        :type board: List[List[int]]
        :rtype: int
        """
        n = len(board)
        rcount = ccount = 0
        for j in xrange(n):
            if board[0][j]==1:
                rcount += 1
            if board[j][0]==1:
                ccount += 1
        if n%2==0:
            if rcount!=n/2 or ccount!=n/2:
                return -1
        else:
            if (rcount!=n//2 and rcount!=n//2+1) or (ccount!=n//2 and ccount!=n//2+1):
                return -1
        for i in xrange(1,n):
            rsame = board[i][0]==board[i-1][0]
            csame = board[0][i]==board[0][i-1]
            for j in xrange(1,n):
                if (rsame and board[i][j]!=board[i-1][j]) or (not rsame and board[i][j]==board[i-1][j]):
                    return -1
                if (csame and board[j][i]!=board[j][i-1]) or (not csame and board[j][i]==board[j][i-1]):
                    return -1
        if n%2!=0:
            rb = 0 if rcount==n//2 else 1
            cb = 0 if ccount==n//2 else 1
            diff = 0
            for j in xrange(n):
                if board[0][j]!=rb:
                    diff += 1
                if board[j][0]!=cb:
                    diff += 1
                rb = 1-rb
                cb = 1-cb
            return diff//2
        else:
            rb = cb = 0
            rdiff = cdiff = 0
            for j in xrange(n):
                if board[0][j] != rb:
                    rdiff += 1
                if board[j][0] != cb:
                    cdiff += 1
                rb = 1 - rb
                cb = 1-cb
            return min(n-rdiff,rdiff)//2+min(n-cdiff,cdiff)//2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值