最少交换次数python_leetcode第200周赛第三题leetcode1536. 排布二进制网格的最少交换次数...
leetcode1536. 排布二進制網格的最少交換次數
給你一個 n x n 的二進制網格 grid,每一次操作中,你可以選擇網格的 相鄰兩行 進行交換。
一個符合要求的網格需要滿足主對角線以上的格子全部都是 0 。
請你返回使網格滿足要求的最少操作次數,如果無法使網格符合要求,請你返回 -1 。
主對角線指的是從 (1, 1) 到 (n, n) 的這些格子。
示例 1:
輸入:grid = [[0,0,1],[1,1,0],[1,0,0]]
輸出:3
示例 2:
輸入:grid = [[0,1,1,0],[0,1,1,0],[0,1,1,0],[0,1,1,0]]
輸出:-1
解釋:所有行都是一樣的,交換相鄰行無法使網格符合要求。
示例 3:
輸入:grid = [[1,0,0],[1,1,0],[1,1,1]]
輸出:0
提示:n == grid.length
n == grid[i].length
1 <= n <= 200
grid[i][j] 要么是 0 要么是 1 。
方法:貪心+后綴0
思路:
首先我們考慮題意,成功變換之后,對于i行,這一行需要有n-i-1個后綴0,grid[i][i+1]......grid[i][-1]都為0。對于最后一行,不需要有后綴0。
由于我們只能變換相鄰的兩行,對于列是改變不了的。那么現存的每一行的后綴0的數量是不會改變的,因此,我們使用一個數組row_zeros,來保存每一行的后綴0數量,當需要交換的時候,只需要交換這個數組中的對應兩行的值,而不需要交換grid,大大減少了時間復雜度。也就是說,在遍歷完grid,計算出row_zeros之后,我們就不需要grid了。
下面我們考慮如何計算。因為越上面的行,對后綴0的要求越高,所以我們從i=0行開始往下遍歷,直到倒數第二行(因為最后一行不需要)。遍歷的過程中,可能出現幾種情況:row_zeros[i] >= n-i-1;說明該行已經滿足條件了,那么我們這一行就不需要替換了。(不用擔心這一行搶了后面需要的行,因為后面的行要求肯定比這一行低。也不用擔心這一行沒有用更好的行,比如這一行后綴和要求5,這一行是5,后面還有一行后綴和是6,因為5已經滿足了條件,后面的6一定可以滿足它所對應的那一行的條件,不會造成影響,盡可能的少的進行行的變換。)
如果小于,那么這行需要互換,我們從這一行下面的i+1開始往后遍歷,找到第一個滿足條件的行(貪心,第一個找到的需要變換的次數最小)。然后將這一行往上一行一行交換到i行,交換的時候只需要互換row_zeros,交換使用res計數。
如果遍歷到了末尾行還沒找到滿足要求的,那么說明答案不存在,直接返回-1。
遍歷完所有行,返回計數的res。
代碼:
Python3:
class Solution:
def minSwaps(self, grid: List[List[int]]) -> int:
res = 0
n = len(grid)
# row_zeros[i]表示i行的后綴0個數
row_zeros = [0] * n
# 遍歷,填寫row_zeros
for i in range(n):
for j in range(n-1,-1,-1):
if grid[i][j] == 0:
row_zeros[i] += 1
else:
break
# 從第一行開始遍歷,到倒數第二行
for i in range(n-1):
# 如果該行的后綴0滿足要求,pass
if row_zeros[i] >= n-i-1:
pass
# 不符合要求,從下一行開始,找到第一個滿足條件的
else:
for j in range(i+1,n):
if row_zeros[j] >= n-i-1:
break
# 找到這一行,將符合條件這個一次一次往上面互換,換到i行
# 互換的時候,只需要互換row_zeros對應的值即可,不需要互換grid
if row_zeros[j] >= n-i-1:
for k in range(j,i,-1):
row_zeros[k],row_zeros[k-1] = row_zeros[k-1],row_zeros[k]
res += 1
# 如果沒找到,說明不存在符合的i行的行,返回-1
else:
return -1
# 最后返回res
return res
cpp:
class Solution {
public:
int minSwaps(vector>& grid) {
int res = 0;
int n = grid.size();
// row_zeros[i]表示i行的后綴0個數 vector row_zeros(n,0);
// 遍歷,填寫row_zeros for (int i = 0; i < n; ++i)
for (int j = n-1;j > -1;--j){
if (grid[i][j] == 0)
row_zeros[i] += 1;
else break;
}
// 從第一行開始遍歷,到倒數第二行 for (int i = 0; i < n-1; ++i){
// 如果該行的后綴0滿足要求,pass if (row_zeros[i] >= n-i-1) continue;
// 不符合要求,從下一行開始,找到第一個滿足條件的 else{
int j = i+1;
for (;j < n-1; ++j){
if (row_zeros[j] >= n-i-1){
break;
}
}
// 找到這一行,將符合條件這個一次一次往上面互換,換到i行 // 互換的時候,只需要互換row_zeros對應的值即可,不需要互換grid if (row_zeros[j] >= n-i-1){
for (int k = j; k > i; --k){
swap(row_zeros[k],row_zeros[k-1]);
res ++;
}
}
// 如果沒找到,說明不存在符合的i行的行,返回-1 else return -1;
}
}
// 最后返回res return res;
}
};
結果:
總結
以上是生活随笔為你收集整理的最少交换次数python_leetcode第200周赛第三题leetcode1536. 排布二进制网格的最少交换次数...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实例化对象有new吗_PHP
- 下一篇: python连接oracle数据库_深入