LeetCode 每日一題765. 情侶牽手
阿新 • • 發佈:2021-02-15
765. 情侶牽手
N 對情侶坐在連續排列的 2N 個座位上,想要牽到對方的手。 計算最少交換座位的次數,以便每對情侶可以並肩坐在一起。 一次交換可選擇任意兩人,讓他們站起來交換座位。
人和座位用 0
到 2N-1
的整數表示,情侶們按順序編號,第一對是 (0, 1)
,第二對是 (2, 3)
,以此類推,最後一對是 (2N-2, 2N-1)
。
這些情侶的初始座位 row[i]
是由最初始坐在第 i
個座位上的人決定的。
示例 1:
輸入: row = [0, 2, 1, 3] 輸出: 1 解釋: 我們只需要交換row[1]和row[2]的位置即可。
示例 2:
輸入: row = [3, 2, 0, 1]
輸出: 0
解釋: 無需交換座位,所有的情侶都已經可以手牽手了。
說明:
len(row)
是偶數且數值在[4, 60]
範圍內。- 可以保證
row
是序列0...len(row)-1
的一個全排列。
方法一:貪心
解題思路
遍歷偶數位置,如果奇數位置不是情侶號碼,去找到情侶號碼並和奇數位置交換。
為什麼可以直接使用貪心演算法呢?
- 當有 2 隊情侶錯位時,至少交換 1 次;有 3 隊情侶錯位時,至少交換 2 次;以此類推,有 m 隊情侶錯位時,至少交換 m - 1 次。
- 基於上述說明,為什麼不能直接遍歷陣列找出有多少隊情侶錯位(假設為 k),直接返回
k - 1
[0,2,1,3,4,6,5,7]
,可見四隊情侶都分開了,但是隻用交換[2,1]
和[5,6]
一共兩次就能讓四隊情侶挨著坐。原因是[0,2,1,3]
和[4,6,5,7]
在不同的 “圖” 中,即通過旁邊的人或情侶找到的人才屬於同一個 “圖”(遞迴查詢)。 - 對於每一個 “圖”,假設圖有 n 隊情侶,至少需要
n - 1
次交換讓圖中情侶坐在一起。上面例子一共兩個圖,每個圖中兩隊情侶,每個圖交換一次共交換兩次就行了。 - 貪心演算法,保證了每次交換的號碼都在同一個圖中,不會交換本圖以外的號碼,所以使用貪心演算法的交換次數就是最少交換次數。
參考程式碼
- 暴力查詢:時間複雜度 O(n2),空間複雜度 O(1)
public int minSwapsCouples(int[] row) {
int n = row.length;
int ret = 0;
for (int i = 0; i < n; i += 2) {
int lover = (row[i] % 2 == 0) ? row[i] + 1 : row[i] - 1;
if (lover == row[i + 1]) {
continue;
}
for (int j = i + 2; j < n; j++) {
if (lover == row[j]) {
row[j] = row[i + 1];
row[i + 1] = lover;
break;
}
}
ret += 1;
}
return ret;
}
- 優化,使用雜湊表記錄每個號碼的角標,查詢的時候直接查詢雜湊表,交換後更新雜湊表:時間複雜度 O(n),空間複雜度 O(n)
public int minSwapsCouples(int[] row) {
int n = row.length;
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < n; i++) {
map.put(row[i], i);
}
int ret = 0;
for (int i = 0; i < n; i += 2) {
int lover = row[i] ^ 1;
if (lover == row[i + 1]) {
continue;
}
int j = map.get(lover);
row[j] = row[i + 1];
row[i + 1] = lover;
map.put(lover, i + 1);
map.put(row[j], j);
ret += 1;
}
return ret;
}
執行結果
- 圖片是暴力查詢的結果,資料量過小導致暴力法時間優於雜湊表。