题目
解法:
将2D问题转化为1D,然后贪心的移动
class Solution:
def minSwaps(self, grid: List[List[int]]) -> int:
n = len(grid)
# take this as a 1-d problem,count the continues 0 from the end in every row. What we need to do is to put the rows at the correct posistion.
zero_count = []
for i in range(n):
count = 0
for j in range(n-1,-1,-1):
if grid[i][j]:
break
count += 1
zero_count.append(count)
# for ith from the first row to the last, we greedyly find the satisfied row to put at the ith position. When i is at the end, we have placed all the rows at correct position
# moves counts the total swaps needed
moves = 0
for i in range(n):
if zero_count[i]<n-i-1:
# i is the current row position we need to put the satisfied row
pos = i
# we move down until find the satisfied row
while pos<n and zero_count[pos]<n-i-1:
pos += 1
# if we can't find the satisfied row for current i, return -1
if pos==n:
return -1
# we swap the pos row with the pos-1 row until to the ith row. But here we actually only need to swap the zero_count list
while pos>i:
zero_count[pos],zero_count[pos-1] = zero_count[pos-1],zero_count[pos]
pos -= 1
moves+=1
return moves
二刷
两个问题需要证明:
- 为什么往后找到第一个符合条件的行就可以,而不是需要找到刚好符合的那一行。比如当前行需要10个tailing zero,我们最先找到的一行有1000个tailing zero,那么把这行作为目标行是肯定没有问题的,因为当前行之后的所有行需要的tailing zero数量肯定比当前行少,所以可以优先满足当前行,这是greedy的思想(
Suppose, current row (i-th row) asks for a row with at least 4 zeros, and the neaerst downward row (j-th) has 5 tailing zeros. You can greedily but aslo safely choose it as candidate. any rows after than i-th row will ask for less than 4 tailing rows. So you greedy approach will cause no trouble at all.
) - 为什么这么移动是最优的,感觉不太好证明,因为每次移动都会改变其它行的位置,所以一开始才会想到用最短路径的方法来解决
class Solution {
public:
int minSwaps(vector<vector<int>>& grid) {
int n = grid.size();
vector<int> zero_count(n,0);
for(int i=0;i<n;i++){
int cnt = 0;
for(int j=n-1;j>=0;j--){
if(grid[i][j] != 0){
break;
}
cnt++;
}
zero_count[i] = cnt;
// cout << cnt << endl;
}
int moves = 0;
for(int i=0;i<n;i++){
int curr_row = i;
while(curr_row < n && zero_count[curr_row] < n-i-1) curr_row++;
if(curr_row == n) return -1;
while(curr_row > i){
swap(zero_count[curr_row],zero_count[curr_row-1]);
curr_row--;
moves++;
}
}
return moves;
}
};
时间复杂度:O(n^2), 来自于第二个for循环,每行访问一次,每次访问至多移动n个位置
空间复杂度:O(n)