这周因为两道题目都只想到了一种解法,所以写在一起。
1. Swim In Rising Water
On an N x N grid
, each square grid[i][j]
represents the elevation at that point (i,j)
.
Now rain starts to fall. At time t
, the depth of the water everywhere is t
. You can swim from a square to another 4-directionally adjacent square if and only if the elevation of both squares individually are at most t
. You can swim infinite distance in zero time. Of course, you must stay within the boundaries of the grid during your swim.
You start at the top left square (0, 0)
. What is the least time until you can reach the bottom right square (N-1, N-1)
?
Example 1:
1 | Input: [[0,2],[1,3]] |
Example 2:
1 | Input: [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]] |
Note:
2 <= N <= 50
.- grid[i][j] is a permutation of [0, …, N*N - 1].
解法
这道题的意思是,在t时刻,海拔为t,而n*n的二维矩阵的每个数值都代表了一处的海拔,从一点游到另一点的条件是两处的海拔(值)都大于等于t,要求求出从(0,0)到(n-1,n-1)的最小时间。也就是一个搜索节点的问题,可以用bfs即广度优先搜索的思路来做。
在寻找足够大的t时,我用二分法来实现,这样又可以节约不少时间:
1 | int swimInWater(vector<vector<int>>& grid) { |
真正的实现函数里,bfs用一个queue来实现,还要一个二维vector来记录已经到过的节点。然后就是每次把和节点相邻的未经过的节点(且是数值小于等于t的)加入bfs,并把现有节点pop出去,看能否在bfs为空之前找到终点。
1 | bool swim(vector<vector<int>>& grid, int t){ |
这样就完成了这一道题。
2. Couples Holding Hands
N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum number of swaps so that every couple is sitting side by side. A swap consists of choosing any two people, then they stand up and switch seats.
The people and seats are represented by an integer from 0
to 2N-1
, the couples are numbered in order, the first couple being (0, 1)
, the second couple being (2, 3)
, and so on with the last couple being (2N-2, 2N-1)
.
The couples’ initial seating is given by row[i]
being the value of the person who is initially sitting in the i-th seat.
Example 1:
1 | Input: row = [0, 2, 1, 3] |
Example 2:
1 | Input: row = [3, 2, 0, 1] |
Note:
len(row)
is even and in the range of[4, 60]
.row
is guaranteed to be a permutation of0...len(row)-1
.
解法(伪)
在这道题目中,有许多对couple,他们是(0, 1), (2, 3), …, (2n-2, 2n-1)。现在它们的顺序被打乱了,而你可以随即调换元素的位置,你需要找到调换次数最少的方案。
我的做法是简单的在判断两个元素不是一对couple后,往后查找它的couple并替换,同时调换次数增加一次。
1 | int minSwapsCouples(vector<int>& row) { |
你以为这样就结束了吗?
cyclic swapping
上面的解法是在循环中嵌套一个循环,效果显然是不行的,通过leetcode的discuss,我学到了一种更为优秀的解法:cyclic swapping。
这个解法的精华在于:i == ptn[pos[ptn[row[i]]]]
,乍一看确实毫无头绪,但要首先了解两个额外设置的数组ptn
和pos
:
ptn[i]
指的是标签i的couple的值(i可以是位置也可以是具体的值)—— 若i为偶数,ptn[i] = i + 1
,若i为奇数,ptn[i] = i - 1
。pos[i]
指的是标签i在row数组(也就是给定的随机数组)中的index ——row[pos[i]] == i
。
这样一来,i == ptn[pos[ptn[row[i]]]]
的意思就是:
- 在位置i上的元素有值
row[i]
,我们想把它放在它couple的旁边。 - 首先找到它的couple的值,也就是
ptn[row[i]]
。 - 接着找到这个couple的位置,也就是
pos[ptn[row[i]]]
。 - 最后找到这个位置旁的位置,也就是
ptn[pos[ptn[row[i]]]]
。
接着就可以进行调换了:
1 | int minSwapsCouples(vector<int>& row) { |