当前位置: 首页 > biancheng >正文

leetcode 第309场周赛题解:

LeetCode 2399. 检查相同字母间的距离 

题目链接:

2399. 检查相同字母间的距离 - 力扣(LeetCode)

时间复杂度O(n ^ 2)

class Solution {
public:
    bool checkDistances(string s, vector<int>& distance) {
        int n = s.size();
        bool st[30] = {false};
        int ans[30] = {0}; 
        for (int i = 0; i < n; i ++ )
        {
            if (!st[s[i] - 'a'])//如果s[i]是第一次出现
                for (int j = 0; j < n; j ++ )
                {
                    if (s[i] == s[j]) ans[s[i] - 'a'] = j - i - 1;//记录两个s[i]中间有多少个数
                    st[s[i] - 'a'] = true;//将s[i]定义为被计算过
                }
        }

        for (int i = 0; i < 26; i ++ )  //若s[i]出现过且distance不与ans相同返回false
            if (st[i] && distance[i] != ans[i]) return false;
        
        return true;
    }
};

LeetCode 2400. 恰好移动 k 步到达某一位置的方法数目

题目链接:

2400. 恰好移动 k 步到达某一位置的方法数目 - 力扣(LeetCode)

时间复杂度(nlogn)

设r为向右走的步数,l 为向左走的步数 m = abs(endPos - startPos)

则由题意可得:r - l = m, r + l = k 即:r = (m + k) / 2

因为每一次确定的r都有唯一的l与之对应,所以总方案数位Cn, r(C是组合数,n是底数)

class Solution {
    typedef long long LL;
    const int mod = 1e9 + 7;
    
public:
    
    int qmi(int a, int b)
    {
        int res = 1;
        while (b)
        {
            if (b & 1) res = (LL)res * a % mod;
            a = (LL)a * a % mod;
            b >>= 1;
        }
        
        return res;
    }
    int numberOfWays(int s, int e, int k) {
        int m = abs(e - s);
        int r = m + k >> 1;
        if ((m + k) % 2 || k < m) return 0;//若(m + k) % 2 != 0即r = (m + k) / 2
                                           //为浮点数则无解,若题目要求的步数k小于他们直接的间距
        int res = 1;//求组合数
        for (int i = k; i > k - r; i -- ) res = (LL)res * i % mod;
        for (int i = 1; i <= r; i ++ ) res = (LL)res * qmi(i, mod - 2) % mod;
        
        return res;
    }
};

LeetCode 2401. 最长优雅子数组  

题目链接:

2401. 最长优雅子数组 - 力扣(LeetCode)

时间复杂度: O(nlogn)

利用双指针算法,将十进制转化为二进制找出[0, 30]位中1每个位置的1恰好出现一次,记录最大长度即可

class Solution {
public:
    int longestNiceSubarray(vector<int>& nums) {
        int cnt[40] = {0};
        int res = 0;
        for (int i = 0, j = 0, tot = 0; i < nums.size(); i ++ )
        {//tot表示某个位置1出现的次数大于1的个数, 双指针算法的位置: i在j后面
            for (int k = 0; k < 31; k ++ )
                if (nums[i] >> k & 1)//若第k位是1
                    if (++ cnt[k] > 1)//若加上之前的数,第k位出现的1的数目大于1
                        tot ++ ;//tot 加1
            
            while (tot)//找出当tot == 0时j的位置,即枚举到每个二进制上恰好只有一个1位置
            {
                for (int k = 0; k < 31; k ++ )
                    if (nums[j] >> k & 1)
                        if (-- cnt[k] == 1)//若下标从j到i之间二进制的第k恰好只出现一次
                            tot -- ;
                j ++ ;//j往后移一个直到满足:从下表j 到 i 之间每个二进制上恰好只有一个1位置
            }
            
            res = max(res, i - j + 1);//记录长度
        }
        
        return res;
    }
};

LeetCode 2402. 会议室 III 

题目链接:

2402. 会议室 III - 力扣(LeetCode)

时间复杂度O(nlogn)

1:将会议按照开始时间从小到大排序,依次将会议分配给会议室。
2:定义两个小跟堆,busy和 idle,分别表示忙碌的会议室和空闲的会议室。
3:忙碌的堆由二元组 (结束时间,该会议编号)组成,堆顶为结束时间最近的会议室。
4:空闲的堆由会议室编号组成,每次取出的都是空闲的且编号最小的会议室。
5:遍历会议,对于当前会议 (st,ed),将所有忙碌会议室的结束时间在 st 之前的会议室全部设置为空闲,并插入到空闲的堆中。
6:如果空闲的堆不为空,则取出会议室编号最小的堆,分配给当前会议,然后插入到忙碌的堆。
7:如果不存在空闲的会议室,则需要取出当前忙碌的堆中结束时间最早的会议室,分配给当前会议,然后插入到忙碌的堆。
如此重复,过程中记录下每个会议室的使用次数。

typedef long long LL;
typedef pair<LL, int> PLI;

#define x first
#define y second

class Solution {
public:
    int mostBooked(int n, vector<vector<int>>& meetings) {
        vector<int> cnt(n, 0);//记录使用会议室出现的次数
        priority_queue<int, vector<int>, greater<int>> idle;//记录空闲会议室的编号
        priority_queue<PLI, vector<PLI>, greater<PLI>> busy;//记录忙碌会议室。

        sort(meetings.begin(), meetings.end());
        for (int i = 0; i < n; i ++ ) idle.push(i);//开始时所有会议室都是空闲会议室
        
        for (auto &p : meetings)
        {
            while (busy.size() && busy.top().x <= p[0])//当某个会议室结束,且该会议室结束的时间
            {                                          //小于当前会议开始的时间,则把他压入空闲会议室
                idle.push(busy.top().y);
                busy.pop();
            }

            if (idle.size())//若有空闲会议室,分配空闲会议室作为会议室参加
            {
                int t = idle.top();//找出最小的编号
                idle.pop();
                busy.push({p[1], t});//该会议在这个空闲会议室t举办
                cnt[t] ++ ;//t的使用次数加一
            }
            else//若没有空闲会议室,即所有会议室都满了
            {
                auto t = busy.top();//找出最找结束的会议
                busy.pop();
                cnt[t.y] ++ ;//该会议使用次数加一
                busy.push({t.x + p[1] - p[0], t.y});//该会议结束时间 == 上一次会议结束时间t.x + 
                                                    //会议持续时间 p[1] - p[0]
            }
        }

        int ans = 0;
        for (int i = 1; i < n; i++)//找出举办最多会议的房间编号
            if (cnt[i] > cnt[ans])
                ans = i;
        
        return ans;
    }
};

相关文章:

  • switch循环语句
  • 牛客练习赛#84 F 莫比乌斯反演+杜教筛+技巧+斐波那契数列和gcd的结论+矩阵快速幂
  • ZZNUOJ_用C语言编写程序实现1342:支配值数目(附完整源码)
  • java毕业设计后勤管理系统餐饮评价监督系统(附源码、数据库)
  • 前端基础学习笔记
  • 【TS】联合类型--类型断言--类型推断
  • 谈笑风声的秘密
  • QT影城网上售票系统
  • NetCDF数据在ArcMap中的使用
  • 打怪升级(考验思路)