参加 LeetCode week-200 的周赛,遇到一道很有意思的题,卡了很久,结束后看了大佬的解题思路,顿时豁然开朗,遂提笔记录一下
题目
1536. Minimum Swaps to Arrange a Binary Grid
Given an n x n
binary grid, in one step you can choose two adjacent rows of the grid and swap them.
A grid is said to be valid if all the cells above the main diagonal are zeros.
Return the minimum number of steps needed to make the grid valid, or -1 if the grid cannot be valid.
The main diagonal of a grid is the diagonal that starts at cell (1, 1) and ends at cell (n, n).
Constraints:
n == grid.length
n == grid[i].length
1 <= n <= 200
grid[i][j] is 0 or 1
思路
首先是读题,从题目描述中可以得出:
- 每次只能交换相邻两行
- 网格有效条件:最终主对角线以上全是0
题目给的几个样例很有迷惑性,有效条件只要求对角线以上全是0,对主对角线及对角线以下的数字并没有要求,但是以上样例中主对接线全是1,这点可能会有迷惑性。。。
转换下这个问题最终的有效条件,即要求网格:
- 第 0 行,至少要有 n-1 个 0
- 第 1 行,至少要有 n-2 个 0
- …
- 第 i 行,至少要有 n-1-i 个 0
先对网格中每行,算出末尾连续0的个数,这样对整个网格可以得到一个数组,相当于要对这个数组进行排序,排序的方式是逐步交换相邻两个数字,最终停止的条件是,要使得数组中第 i 个位置的数字 >=n-1-i
,上代码展示:
class Solution(object):
def minSwaps(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
# 计算每行末尾连续0的个数
def count_tail_zeros(x):
i = len(x)-1
ret = 0
while(i >= 0 and x[i] == 0):
i -= 1
ret += 1
return ret
v = list()
for x in grid:
v.append(count_tail_zeros(x))
answer = 0
for i in range(len(v)):
# 当前行0的个数 < n-1-i,则需要进行交互
if v[i] < len(v) - 1 - i:
# 能不能在后面的数字中找到一个 >= n-1-i 的数字
find = False
for j in range(i+1, len(v)):
# 找到一个满足条件的数字,移动到上面去
if v[j] >= len(v) - 1 - i:
# 逐步交换到 v[i] 的位置
while v[i] < len(v) -1 - i:
v[j-1],v[j] = v[j],v[j-1]
answer += 1
j -= 1
find = True
break
# 没有找到,则不可能有效,直接返回 -1
if not find:
return -1
return answer