【算法练习】leetcode每日一题/并查集/贪心 765. 情侣牵手

目录

765. 情侣牵手

方法一 并查集

思路

代码

方法二 贪心

思路

代码


765. 情侣牵手

难度困难199

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
解释: 无需交换座位,所有的情侣都已经可以手牵手了。

说明:

  1. len(row) 是偶数且数值在 [4, 60]范围内。
  2. 可以保证row 是序列 0...len(row)-1 的一个全排列。

 

方法一 并查集

思路

自己想到了并查集,但是没有很好的联系到题目,还是参考别人的题解理解的。

节点是情侣对数的编号,遍历每对位置上

首先,我们总是以「情侣对」为单位进行设想:

对于每对相邻的位置,如果是第 i 对与第 j 对坐在了一起,则在 i 号节点与 j 号节点之间连接一条边,代表需要交换这两对情侣的位置。

当有两对情侣相互坐错了位置,ta们两对之间形成了一个环。需要进行一次交换,使得每队情侣独立(相互牵手)

如果三对情侣相互坐错了位置,ta们三对之间形成了一个环,需要进行两次交换,使得每队情侣独立(相互牵手)

如果四对情侣相互坐错了位置,ta们四对之间形成了一个环,需要进行三次交换,使得每队情侣独立(相互牵手)

也就是说,如果我们有 k 对情侣形成了错误环,需要交换 k - 1 次才能让情侣牵手。

作者:AC_OIer
链接:https://leetcode-cn.com/problems/couples-holding-hands/solution/liang-chong-100-de-jie-fa-bing-cha-ji-ta-26a6/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

假设形成cnt个环,环的节点数分别为 {k1,k2...} 

则 ans=k1-1 + k2-1 + ...kcnt-1 = (k1+k2+...)-cnt=m-cnt

代码

参考官方的思路 直接加的k1-1 + k2-1 + ...kcnt-1

class Solution {
public:
    vector<int> fa;
    int findRoot(int x){
        if(fa[x]==-1)
            return x;
        int tmp=findRoot(fa[x]);
        fa[x]=tmp;
        return tmp;
    }
    void add(int x,int y){
        x=findRoot(x);
        y=findRoot(y);
        if(x!=y){
            fa[x]=y;
        }
    }
    int minSwapsCouples(vector<int>& row) {
        //并查集
        int n=row.size()/2;  //情侣的对数
        fa=vector<int>(n,-1);//初始化为-1
        for(int i=0;i<row.size();i+=2){
            int a=row[i]/2;
            int b=row[i+1]/2;
            add(a,b);
        }
        map<int,int> rootcount;
        for(int i=0;i<n;i++){
            int t=findRoot(i);
            rootcount[t]++;   //统计了每个环的父节点 每个环的结点数
        }
        int ans=0;
        for(auto it=rootcount.begin();it!=rootcount.end();it++){
            ans+=(it->second-1);  //累加k-1
        }
        return ans;
    }
};

修改后的题解,不需要统计每个环父节点:

class Solution {
public:
    vector<int> fa;
    int findRoot(int x){
        if(fa[x]==-1)
            return x;
        int tmp=findRoot(fa[x]);  //没有写fa[x]
        fa[x]=tmp;
        return tmp;
    }
    void add(int x,int y){
        x=findRoot(x);
        y=findRoot(y);
        if(x!=y){
            fa[x]=y;
        }
    }
    int minSwapsCouples(vector<int>& row) {
        //并查集
        int n=row.size()/2;  //情侣的对数
        fa=vector<int>(n,-1);//初始化为-1
        for(int i=0;i<row.size();i+=2){    //i的最值是row.size
            int a=row[i]/2;
            int b=row[i+1]/2;
            add(a,b);
        }
        int count=0;
        for(int i=0;i<n;i++){
            if(fa[i]==-1)
                count++;
        }

        return n-count;
    }
};

方法二 贪心

思路

代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值