力扣题:634寻找错位排列

25 篇文章 2 订阅

首先直接暴力的时间复杂度很大,下面先贴一个暴力法的结果,然后再是动态规划

class Solution {
public:
    int num=0;
    void dfs(int &sum,int &cur,vector<int> &re,vector<int> &der)
    {
       // if(cur>=re.size()) return;
        if(sum==re.size()-1&&cur>=re.size()) {//说明一次排列完成
            num++;
            return;
            }
          for(int i=cur;i<re.size();++i)
          {
             // if(der[i]==0)//i位置未放置数字,则开始放置
              //{//cur位置还没放置数字
                   for(int j=1;j<re.size();++j)//找到一个可以放置的数字开始放置
                   {
                            if(re[j]==0&&j!=i)//找到一个符合规则的数字
                           {
                                re[j]=1; der[i]=1;// result[i]=j;
                                sum++;cur++;
                                dfs(sum,cur,re,der);
                                 re[j]=0; 
                                 der[i]=0; //回溯
                                 //result[i]=0;
                                 sum--;cur--;
                                 break;  //找到一条路径
                           } 
                     
                   }
             // }
          }
    }

    int findDerangement(int n) {
       //经典全排列,考虑使用dfs
        vector<int> re(n+1,0);//用来标记该下标的数字是否放置过
        vector<int> der(n+1,0);//用来标记是否已经放置了数字
        //vector<int> result(n+1,0);//用来标记是否已经放置了数字
        int a=0,b=1;
        dfs(a,b,re,der);
        return num;
    }
};

n=10 时:

n=11:

n=12:  暴力法的耗时炸了,十倍增长,恐怖如斯

 

下面就要有请万能的动态规划了:

一共有n个数,假设第k个数被放置在非k的x位置,那么就需要对剩下的数接着进行错位排列:

一种直接k与x互换,那么相当于剩下n-2个数的错位排序

一种x不能放在k位置上,其他非k非x的数i,不能放在i位置上,这样从整体上看就还是n-1个数的错位排列

方法有的时候比努力重要的多啊(指好的算法比暴力好多了)

 

那么记f(n)为n个数错位排列的种类,则有

f(n)=(f(n-1)+f(n-2)) *(n-1)

代码:  时间复杂度O(n),空间复杂度O(1)

class Solution {
public:
    int findDerangement(int n) {
      long long f1=0,f2=1,fn=1;
       if(n<=1) return 0;
       if(n==2) return 1;
       for(int i=3;i<=n;i++)
       {
           fn=(f1+f2)*(i-1)%(1000000007);
           f1=f2;
           f2=fn;
       }
       return fn;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

溯夜流云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值