leetcode第301场周赛

第一题:2335. 装满杯子需要的最短总时长

签到题,简单来说就是一共三个数,有两个操作:1,一个数减一;2,两个数减一;

问最少操作多少次使三个数都为0。

最直观的想法就是每次都对三个数排序,每次都进行第二种操作,最后第一种操作;

故代码如下:

class Solution {
public:
    int fillCups(vector<int>& amount) {
        int res=0;
        while(amount[0]+amount[1]+amount[2])
        {
            sort(amount.begin(),amount.end());//排序
            amount[2]--;//最大数减一
            if(amount[1]) amount[1]--;//次大数非0减一
            res++;
        }
        return res;
    }
};

下面讲讲对上述的优化

第一步还是对三个数进行排序,假设最大数a[2],次大数a[1],最小数a[0],根据对问题的考虑可以将三个数分成两种情况;

1,a[2]>a[0]+a[1],最大数大于剩余两数之和,所以答案就是a[2],因为这里每次都能进行第二种操作,最后又回到操作最大数剩余的数上,所以此时答案就是a[2]。

2,a[2]<=a[0]+a[1],这种情况的话就是保证了每次都能进行第二次操作,除了最后一次以外,故最后答案为(a[2]+a[0]+a[1])/2(上取整)

综上,代码如下:

class Solution {
public:
    int fillCups(vector<int>& a) {
        sort(a.begin(),a.end());
        if(a[2]>a[0]+a[1]) return a[2];
        return (a[0]+a[1]+a[2]+1)/2;
    }
};

第二题:2336. 无限集中的最小数字

问题在于维护一个集合,初始为正整数的集合,共两个操作;

1,移除并返回最小整数

2,添加一个数

且操作次数只有1000次,故选择定义一个set自动排序和判重

代码如下:

class SmallestInfiniteSet {
public:

    set<int> S;
    SmallestInfiniteSet() {
        for(int i=1;i<=1000;i++)
        S.insert(i);
    }
    
    int popSmallest() {
        int t=*S.begin();
        S.erase(S.begin());
        return t;
    }
    
    void addBack(int num) {
        S.insert(num);
    }
};

第三题:2337. 移动片段得到字符串

 下图为原题题意和样例

先分析一下问题,要想答案为true,首先要求start与target的长度一致,且相对数据不变即L和R不能相互跨越,代码如下,详细注释在代码中体现:

class Solution {
public:
    bool canChange(string a, string b) {
        int n=a.size();
        int j=0;//开辟双指针
        for(int i=0;i<n;i++)
        {
            if(a[i]=='_') continue;//空位跳过
            while(j<n&&b[j]=='_') j++;//j也相同,在不越界的情况下空位跳过
            if(j==n) return false;//j等于n表示没有字符互相对应
            if(a[i]!=b[j]) return false;//同上
            if(a[i]=='L'&&i<j) return false;
            if(a[i]=='R'&&i>j) return false;
            j++;
        }

        for(int i=j;j<n;j++)
        {
            if(b[i]!='_') return false;//判断第二串有没多一些字符
        }
        return true;
    }

};

第四题:2338. 统计理想数组的数目

 给定n,m要求数组大小在n和m之间且每一个数是前面一个数的倍数,求方案数量。

题目给定的数据范围较小,m最大10000,所以数据限制在2的0次方到2的13次方8192之间。

我们假定数组中所有数字不同,则序列长度最后长度只有14,暴搜能过

class Solution {
public:
    int n,m;
      int ans=0;
      const int MOD=1e9+7;
      vector<vector<int>> f;

      void dfs(int u,int cnt)
      {
          ans=(ans+f[n-1][cnt-1])%MOD;
          if(cnt<n){
              for(int i=2;i*u<=m;i++)
              {
                  dfs(i*u,cnt+1);
              }
          }
      }
    int idealArrays(int n, int m) {
      this->n=n,this->m=m;
      f=vector<vector<int>>(n,vector<int>(20));
      for(int i=0;i<n;i++)
          for(int j=0;j<20&&j<=i;j++)
          {
              if(!j) f[i][j]=1;
              else f[i][j]=(f[i-1][j] + f[i-1][j-1]) % MOD;
          }
          for(int i=1;i<=m;i++) dfs(i,1);
           return ans;
      
       
    }
};

下面看看dp怎么写

class Solution {
public:
    int idealArrays(int n, int m) {
        const int MOD=1e9+7;
        vector<vector<int>> f(m+1,vector<int>(15));
        for(int i=1;i<=m;i++) f[i][1]=1;
        for(int j=1;j<14;j++)
            for(int i=1;i<=m;i++)
                for(int k=2;k*i<=m;k++)
                    f[k*i][j+1]=(f[k*i][j+1]+f[i][j])%MOD;
        
        vector<vector<int>> C(n,vector<int>(15));
        for(int i=0;i<n;i++)
            for(int j=0;j<=i&&j<=14;j++)
                if(!j) C[i][j]=1;
                else C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
        
        int res=0;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=14&&j<=n;j++)
                res=(res+(long long)f[i][j]*C[n-1][j-1])%MOD;
        return res;
        }
};

这里还涉及了组合数的运用,但算法基础课还没刷完,最后一题能理解的有限,上述代码参考yxc大佬

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值