leetcode.1806 还原排列的最少操作步数 - 模拟 + lcm

​​​​​​1806. 还原排列的最少操作步数

本题是数论题 共介绍4种解题方法

目录

1、所有置换环长度的最小公倍数

2、最小操作数是最大环长度

3、1或n-2所在环长度即为最大置换环长度

4、暴力模拟


思路:

因为数据范围很小 所以可以直接模拟

也可以优化一下——通过样例发现,最少操作数就是最大置换环的长度

更严谨地说,最少操作数 = 所有置换环长度的最小公倍数

 比如上图,n=10

置换环1 :【0】

置换环2 :【1,2,4,8,7,5】 

置换环3:【3,6】

置换环4:【9】

所以我们可以找出所以环长度的最小公倍数就是最少操作数

1、所有置换环长度的最小公倍数

gcd最大公约数

int gcd(int a,int b)
{
    return b!=0? gcd(b,a%b):a;
}

lcm最小公倍数

int lcm=a*b/gcd(a,b);
class Solution {
public:
    int reinitializePermutation(int n) 
    {
        int res=1,cnt;
        for(int i=1;i<n-1;i++) //0和n-1永远是自环 长度为1 不用枚举
        {
            int j=i;
            cnt=0;
            vector<int> st(n,0);
            while(!st[j])
            {
                st[j]=1;
                cnt++;
                j= j&1? n/2+(j-1)/2:j/2;
            }
            res=lcm(res,cnt);
        }
        return res;
    }
};

2、最小操作数是最大环长度

class Solution {
public:
    int reinitializePermutation(int n) 
    {
        vector<int> st(n,0);
        int res=1,cnt;
        for(int i=1;i<n-1;i++) //0和n-1永远是自环 长度为1 不用枚举
        {
            int j=i;
            cnt=0;
            while(!st[j])
            {
                st[j]=1;
                cnt++;
                j= j&1? n/2+(j-1)/2:j/2;
            }
            res=max(res,cnt);
        }
        return res;
    }
};

3、1或n-2所在环长度即为最大置换环长度

通过样例不难发现,下标为1或n-2永远处于最长置换环,所以算出其所在环长度即可

class Solution {
public:
    int reinitializePermutation(int n) 
    {
        int idx=1,res=0;
        do
        {
            idx= idx&1? n/2+(idx-1)/2:idx/2;
            res++;
        }while(idx!=1);
        return res;
    }
};
class Solution {
public:
    int reinitializePermutation(int n) 
    {
        int idx=n-2,res=0;
        do
        {
            idx= idx&1? n/2+(idx-1)/2:idx/2;
            res++;
        }while(idx!=n-2);
        return res;
    }
};

 

4、暴力模拟

class Solution {
public:
    int reinitializePermutation(int n) {
        vector<int> p,t;
        vector<int> a(n,0);
        for(int i=0;i<n;i++) p.push_back(i),t.push_back(i);

        int res=0;
        while(1)
        {
            if(a==t) break;
            for(int i=0;i<n;i++)
            {
                if(i%2==0) a[i]=p[i/2];
                else a[i]=p[n/2+(i-1)/2];
            }
            res++;
            p=a;
        }
        return res;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值