1. 程式人生 > 其它 >LeetCode 每日一題765. 情侶牽手

LeetCode 每日一題765. 情侶牽手

技術標籤:每日一題leetcodejava演算法

765. 情侶牽手

N 對情侶坐在連續排列的 2N 個座位上,想要牽到對方的手。 計算最少交換座位的次數,以便每對情侶可以並肩坐在一起。 一次交換可選擇任意兩人,讓他們站起來交換座位。

人和座位用 02N-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;
}

執行結果

  • 圖片是暴力查詢的結果,資料量過小導致暴力法時間優於雜湊表。
    在這裡插入圖片描述