1284. 转化为全零矩阵的最少反转次数

发布时间 2023-04-04 17:16:35作者: zhangk1988

题目描述

给一个二维矩阵,里面的元素不是0就是1
可以通过翻转完成0-1变换,翻转的限制是周围相邻的点也要跟着变
问最终反转成全0的形式的最小次数?

f1-状态压缩+bfs

基本分析

  1. 看大最少翻转次数可以联想到什么?bfs
  2. 直接bfs有啥问题?(1)矩阵的形式怎么存?通过状态压缩将二维转化为1维度
  3. 要实现以上需求需要做什么?定义encode函数,将mat转化为x;因为枚举翻转点的时候,有需要在mat上操作,所以需要有函数将x解码为mat
  4. 翻转的逻辑?对需要翻转的点,将点和相邻点的值^1
  5. bfs怎么保证不重?对x_cur在入队的时候进行检查,不在vis中的才入队
  6. 对每个点进行枚举之后需要注意什么?因为是本地操作,需要还原现场

代码

class Solution:
    def minFlips(self, mat: List[List[int]]) -> int:

        def encode(mat, m, n):
            x = 0
            for i in range(m):
                for j in range(n):
                    x = x * 2 + mat[i][j]
            return x
        
        def decode(x, m, n):
            mat = [[0] * n for _ in range(m)]
            for i in range(m-1, -1, -1):
                for j in range(n-1, -1, -1):
                    mat[i][j] = x & 1
                    x = x >> 1
            return mat
        
        def convert(mat, m, n, i, j):
            for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1), (0, 0)]:
                if 0 <= i + di < m and 0 <= j + dj < n:
                    mat[i + di][j + dj] ^= 1
        
        m, n = len(mat), len(mat[0])
        x_start = encode(mat, m, n)
        if x_start == 0:
            return 0
            
        vis = {x_start}
        step = 0

        q = deque([x_start])

        while q:
            step += 1
            for _ in range(len(q)):
                mat = decode(q.popleft(), m, n)
                for i in range(m):
                    for j in range(n):
                        convert(mat, m, n, i, j)
                        x_cur = encode(mat, m, n)
                        if x_cur == 0:
                            return step
                        if not x_cur in vis:
                            q.append(x_cur)
                            vis.add(x_cur)
                        convert(mat, m, n, i, j)
        
        return -1

总结

  1. 将矩阵状态压缩为1维,这样矩阵的状态就可以去重和放进队列里面了
  2. 对点修改的时候需要考虑临近的点,这里对mat是本地操作,枚举每个修改的点之后需要还原现场
f1-状态压缩+dfs
待完善