【Leetcode】765. Couples Holding Hands (Couples Holding Hands)


Title description

【Leetcode】765. Couples Holding Hands (Couples Holding Hands)

N couples sit on 2N consecutive seats and want to hold each other's hands. Calculate the minimum number of exchanges of seats so that each couple can sit side by side. You can choose any two people in one exchange and let them stand up and exchange seats.

People and seats are represented by integers from 0 to 2N-1. The lovers are numbered in sequence, the first pair is (0, 1), the second pair is (2, 3), and so on, the last pair is (2N- 2, 2N-1).

The initial seat row[i] of these couples is determined by the person who initially sat in the i-th seat.

Example 1:

输入: row = [0, 2, 1, 3]
输出: 1
解释: 我们只需要交换row[1]和row[2]的位置即可。

Example 2:

输入: row = [3, 2, 0, 1]
输出: 0
解释: 无需交换座位,所有的情侣都已经可以手牵手了。

Description:

  • len(row) is an even number and the value is in the range [4, 60].
  • It can be guaranteed that row is a complete permutation of the sequence 0...len(row)-1.

First answer

Ideas
Greedy method.
What is more difficult and easy to confuse is the following two, how many times you have to move, if you don't want to understand, greed is not necessary. Note that every step greedy takes, the situation it faces needs to be updated, not that every step greedy takes, the situation it faces is still the same.
In the first example, I found that there are 4 numbers (3,1,7,5) to be exchanged before leaving. It is reasonable to exchange 3 times, but in fact, only two exchanges are needed here, because the situation is updated after the first exchange. Because there are only 2 numbers (7,5) to be exchanged.
For the second example, you need to exchange 3 times.
Example 1: [0,3,2,1,4,7,6,5]
Example 2: [0,7,2,1,4,3,6,5]


tese case: [0,2,1,3]
[3, 2, 0, 1]
[0,3,2,1,4,7,6,5]
[0,2,4,6,7,1 , 3,5]
[28,4,37,54,35,41,43,42,45,38,19,51,49,17,47,25,12,53,57,20,2,1, 9,27,31,55,32,48,59,15,14,8,3,7,58,23,10,52,22,30,6,21,24,16,46,5,33, 56,18,50,39,34,29,36,26,40,44,0,11,13]

Code:

class Solution {
    
    
public:
    int minSwapsCouples(vector<int>& row) {
    
    
        // 记录每个元素的索引
        vector<int> from(row.size());
        for(int i=0; i<row.size(); ++i){
    
    
            from[row[i]] = i;
        }

        int count = 0; // 记录操作次数
        for(int i=0; i+1<row.size(); i+=2){
    
    
            // 若不配对
            if(row[i]/2 != row[i+1]/2){
    
    
                count++;
                int other_index = row[i]&0x01 ? from[row[i]-1] : from[row[i]+1];
                swap(row[other_index], row[i+1]);
                swap(from[row[other_index]], from[row[i+1]]);
            }
        }
        return count;
    }
};

result:
Screenshot

Second answer

Idea:
Refer to the official problem solution of leetcode方法二: 循环搜索 【通过】 , which has been explained very well here. Just click the link and see. I am mainly adding a picture here. For picture 1 below, you should have no doubts; but for picture 2 below, some people may be confused. I also thought at first that the first two couples would satisfy the two couples at once. Lovers, at first glance, it seems that two new Unicom components have been added, but in fact, they are still only one Unicom component added.

Insert picture description here Insert picture description here
figure 1 figure 2

According to the above analysis, we find out the number of Unicom components count, and then the result is N-count. As for the number of Unicom components, you can use dfs, or you can use combined search. Here, use combined search.
Code:

// 思路:
// 并查集。2N个座位可以分成N个双人沙发。若所有情侣都成功牵手,则有N个双人沙发。
// 独立沙发:沙发上坐着牵手的情侣
// 联通沙发:沙发上坐着的不是一对情侣,另一半在其他沙发上。
// 联通沙发为2时,交换1次即可
// 联通沙发为3时,交换2次即可
// 联通沙发为4时,交换3次即可,注意,下图不是1个4联通沙发,而是2个2联通的沙发:
// 0,3沙发与2,1沙发2联通,4,7沙发与6,5沙发2联通,所以是2个2联通沙发,所以要操作2个1次,也就是一共要操作2次。
// [0,3,2,1,4,7,6,5]
class Solution {
    
    
public:
    int count;
    vector<int> parents;
    int MyFind(int a){
    
    
        while(a != parents[a]){
    
    
            parents[a] = parents[parents[a]];
            a = parents[a];
        }
        return a;
    }
    void MyUnion(int a, int b){
    
    
        int p1 = MyFind(a);
        int p2 = MyFind(b);
        if(p1 == p2) return;
        parents[p1] = p2;
        count--;
    }
    int minSwapsCouples(vector<int>& row) {
    
    
        int N = row.size() / 2; // 牵手成功后的沙发数量
        count = N;
        parents.clear();
        parents.resize(N);
        for(int i=0; i<N; ++i){
    
    
            parents[i] = i;
        }
        for(int i=0; i+1<row.size(); i+=2){
    
    
            if(row[i]/2 != row[i+1]/2){
    
    
                MyUnion(row[i]/2, row[i+1]/2);
            }
        }

        return N-count;
    }
};

result:
Insert picture description here

Related/reference links

Guess you like

Origin blog.csdn.net/a435262767/article/details/105430636