通过翻转行或列来去除所有的 1 II

Submission

运行时间: 28 ms

内存: 16.7 MB

class Solution:
    def removeOnes(self, grid: List[List[int]]) -> int:
        m,n=len(grid),len(grid[0])
        size=m*n
        #暴力状压
        mask=0
        for i in range(m):
            for j in range(n):
                if grid[i][j]==1:
                    x=i*n+j
                    mask|=(1<<x)
        #BFS爆搜
        quene=deque()
        quene.append(mask)
        vis=set()
        vis.add(mask)
        time=0
        while quene:
            k=len(quene)
            while k:
                stat=quene.popleft()
                if stat==0:
                    return time
                for i in range(m):
                    for j in range(n):
                        x=i*n+j
                        #选定格子
                        if stat>>x&1:
                            cur=stat
                            #以这一行,这一列扩展
                            for t in range(n):
                                #(i,t)
                                now=i*n+t
                                if cur>>now&1:
                                    cur^=(1<<now)
                            for t in range(m):
                                #(t,j)
                                now=t*n+j
                                if cur>>now&1:
                                    cur^=(1<<now)
                            if cur not in vis:
                                vis.add(cur)
                                quene.append(cur)
                k-=1
            time+=1

Explain

这个题解采用了'状态压缩'和'广度优先搜索(BFS)'的方法来解决问题。首先,题解通过状态压缩将二维网格转换成一个整数(位掩码),其中每个位代表网格中的一个元素,1表示该位置是1,0表示该位置是0。接着,使用BFS方法来尝试翻转行或列,并检查每次翻转后的结果。如果达到全0的状态,即完成任务。每次翻转时,将当前状态的所有1都尝试翻转对应的行和列,生成新的状态,并检查是否已生成过这个状态,避免重复工作。这个过程一直持续,直到找到解或遍历完所有可能的状态。

时间复杂度: O((m*n)*2^(m*n))

空间复杂度: O(2^(m*n))

class Solution:
    def removeOnes(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        size = m * n
        # 使用位掩码来表示网格状态
        mask = 0
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    x = i * n + j
                    mask |= (1 << x)
        # 使用BFS搜索所有可能的状态
        queue = deque()
        queue.append(mask)
        visited = set()
        visited.add(mask)
        time = 0
        while queue:
            k = len(queue)
            while k:
                state = queue.popleft()
                if state == 0:
                    return time
                for i in range(m):
                    for j in range(n):
                        x = i * n + j
                        if state >> x & 1:
                            cur = state
                            # 翻转(i, j)所在的行和列
                            for t in range(n):
                                now = i * n + t
                                if cur >> now & 1:
                                    cur ^= (1 << now)
                            for t in range(m):
                                now = t * n + j
                                if cur >> now & 1:
                                    cur ^= (1 << now)
                            if cur not in visited:
                                visited.add(cur)
                                queue.append(cur)
                k -= 1
            time += 1

Explore

在状态压缩中,我们选择一个位掩码来表示整个网格的状态。每个位掩码中的位对应于网格中的一个单元格。为了准确映射每个网格的状态到位掩码,我们定义一个映射方式,通常是行优先或列优先。在这个题解中,我们采用行优先方式,即先遍历每行的所有列。对于一个位置 (i, j),我们将其映射到位掩码中的第 `i * n + j` 位(假设网格宽度为 n)。通过这种方式,每次我们访问或修改网格中的一个元素时,都可以通过计算来准确找到对应的位,并通过位操作(如位与、位或和位异或)来读取或更新其状态。

在这个问题中,我们的目标是找到最快的方式来将网格中所有的 '1' 转换为 '0'。广度优先搜索(BFS)在这种情况下更合适,因为BFS是层次化搜索,它首先探索与起始点距离最近的所有状态,逐层向外扩展。这意味着一旦我们通过BFS找到一个全0的状态,我们可以保证找到的解是需要的最小翻转次数。相比之下,深度优先搜索(DFS)可能会深入探索某一路径而忽略其他更短的解决方案,因此不保证最先找到的解是最优解。

为了避免重复翻转同一行或列导致的无效操作,可以通过记录每一行和每一列的翻转状态来优化。具体方法是维护两个数组,一个用于记录行的翻转状态,另一个用于列的翻转状态。每次翻转时,更新相应行或列的状态。在进行翻转操作前,检查对应行或列的当前状态,如果已经标记为翻转过,则跳过该操作。这样可以减少不必要的重复操作,提高算法的效率。

在算法实现中首先应对特殊边界情况进行处理。对于最小网格大小,如1x1,直接检查单个元素即可。若初始状态已经全部为0,则直接返回0,因为不需要任何翻转。对于全1的初始状态,可以计算翻转整个行和列所需的最小步骤。此外,为了优化算法性能,可以在状态压缩之初就检查网格是否已经是全0状态,从而避免不必要的搜索过程。这样的预处理可以显著减少算法的运行时间,特别是在处理极端或特殊情况时更为有效。