题目描述
给一个二维矩阵,里面的元素不是0就是1
可以通过翻转完成0-1变换,翻转的限制是周围相邻的点也要跟着变
问最终反转成全0的形式的最小次数?
基本分析
- 看大最少翻转次数可以联想到什么?bfs
- 直接bfs有啥问题?(1)矩阵的形式怎么存?通过状态压缩将二维转化为1维度
- 要实现以上需求需要做什么?定义encode函数,将mat转化为x;因为枚举翻转点的时候,有需要在mat上操作,所以需要有函数将x解码为mat
- 翻转的逻辑?对需要翻转的点,将点和相邻点的值^1
- bfs怎么保证不重?对x_cur在入队的时候进行检查,不在vis中的才入队
- 对每个点进行枚举之后需要注意什么?因为是本地操作,需要还原现场
代码
| 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维,这样矩阵的状态就可以去重和放进队列里面了
- 对点修改的时候需要考虑临近的点,这里对mat是本地操作,枚举每个修改的点之后需要还原现场
待完善
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现