LeetCode第243场周赛

第一题 1880. 检查某单词是否等于两单词之和

题目链接:1880. 检查某单词是否等于两单词之和

  • 逐位计算单词之和即可
class Solution {
public:
    int count(string s) {
        int ans = 0;
        for(const auto& c: s) {
            ans = ans * 10 + c - 'a';
        }
        return ans;
    }
    
    bool isSumEqual(string firstWord, string secondWord, string targetWord) {
        return count(firstWord) + count(secondWord) == count(targetWord);
    }
};

第二题 1881. 插入后的最大值

题目链接:1881. 插入后的最大值

  • 如果n是正数,则从左往右找到第一个比x小的数,把x插入到这个数的左边
  • 如果n是负数,则从左往右找到第一个比x大的数,把x插入到这个数的右边
class Solution {
public:
    string maxValue(string n, int x) {
        if(n[0] != '-') {
            int i = 0;
            while(i < n.size() && n[i] - '0' >= x) {
                ++i;
            }
            if(i == n.size()) {
                return n + to_string(x);
            } else {
                return n.substr(0, i) + to_string(x) + n.substr(i);
            }
        } else {
            int i = 1;
            while(i < n.size() && n[i] - '0' <= x) {
                ++i;
            }
            if(i == n.size()) {
                return n + to_string(x);
            } else {
                return n.substr(0, i) + to_string(x) + n.substr(i);
            }
        }
    }
};

第三题 1882. 使用服务器处理任务

题目链接:1882. 使用服务器处理任务

  • 根据题目的规则,我们把服务器分为“空闲的服务器”idle servers和“忙碌的服务器”busy servers
  • 每次一个新的任务到来,都会选择一个“最适合当前任务”的服务器来运行任务
  • 新任务到来时:
    • 如果当前有空闲的服务器,则在空闲的服务器里选择权重最小的服务器运行,如果权重都一样,则选择下标最小的服务器
    • 如果没有空闲的服务器,则会等待忙碌的服务器里第一个运行完任务(变为空闲)的服务器去运行任务;如果多个服务器同时变为空闲,则按照空闲的服务器的排序规则进行选择
  • 根据这个思想,很容易想到用两个优先级队列去维护空闲的服务器is忙碌的服务器bs,两个优先级队列有不同的排序规则
  • 初始时,所有的服务器都是空闲的服务器
  • 因为需要记录忙碌的服务器的完成时间,因此我们构建的服务器结构体包含时间权重下标三个数据成员
  • 对于每个任务,都会从“空闲的服务器”里选择“最合适”的服务器运行任务,这时就把这个服务器从is弹出,加入到bs
  • 如果对于当前任务,没有空闲的服务器,那么就会等忙碌的服务器中出现空闲的服务器,然后再运行任务
class Solution {
private:
    int n, m;
    vector<int> ans;
    
    struct server {
        int time, weight, index;
        server(int t, int w, int i) {
            time = t;
            weight = w;
            index = i;
        }
    };
    
public:
    struct busyServer {                                    // “忙碌的服务器”的优先队列的排序规则
        bool operator() (server a, server b) {
            if(a.time != b.time) {                         
                return a.time > b.time;
            }
            if(a.weight != b.weight) {
                return a.weight > b.weight;
            }
            return a.index > b.index;
        }
    };
    
    struct idleServer {                                   // “空闲的服务器”的优先队列的排序规则
        bool operator() (server a, server b) {
            if(a.weight != b.weight) {
                return a.weight > b.weight;
            }
            return a.index > b.index;
        }
    };
    
    vector<int> assignTasks(vector<int>& servers, vector<int>& tasks) {
        n = servers.size();
        m = tasks.size();
        priority_queue<server, vector<server>, busyServer> bs;
        priority_queue<server, vector<server>, idleServer> is;
        for(int i = 0; i < n; ++i) {
            is.push(server(0, servers[i], i));
        }
        for(int i = 0; i < m; ++i) {
            while(!bs.empty() && bs.top().time <= i) {         // 当前是第 i 秒,忙碌的服务器的优先队列中可能有服务器已经运行完成了,需要弹出堆
                is.push(bs.top());
                bs.pop();
            }
            if(!is.empty()) {                      // 如果有空闲的服务器,则在 is 堆里选择服务器运行,并把服务器加入到 bs 中
                auto t = is.top();
                is.pop();
                ans.push_back(t.index);
                bs.push(server(i + tasks[i], t.weight, t.index));
            } else {                  // 如果没有空闲的服务器,则等待忙碌的服务器中最先运行完成的服务器,在最先完成的服务器中选择服务器运行任务
                auto t = bs.top();
                bs.pop();
                ans.push_back(t.index);
                bs.push(server(t.time + tasks[i], t.weight, t.index));
            }
        }
        return ans;
    }
};

第四题 5775. 准时抵达会议现场的最小跳过休息次数

题目链接:5775. 准时抵达会议现场的最小跳过休息次数

  • dp[i][j]表示经过了前i段道路(i1开始)、跳过j次的最短用时。考虑到精度问题,这里数组是二维的double数组
  • 考虑状态转移,对于dp[i][j]
    • 如果跳过当前道路dist[i - 1],则有:dp[i][j] = dp[i - 1][j - 1] + dist[i - 1] / speed
    • 如果不跳过当前道路dist[i - 1],则有:dp[i][j] = ceil(dp[i - 1][j] + dist[i - 1] / speed)
  • 边界情况:
    • j = 0时,表示我们不跳过任何道路,则dp[i][j]无法由任何“跳过道路”的状态转移得到
    • j = i时,表示我们跳过了所有道路,则dp[i][j]无法由任何“不跳过道路”的状态转移得到
    • 跳过次数j应该小于道路数i
  • 最终答案:
    • 对于所有的小于等于hoursBeforedp[n][i](该状态表示通过了所有道路,跳过i次的最短用时),我们找到最小的那个i,作为结果返回即可
    • 如果在0 ~ n的范围内没有找到满足条件的i,那么返回-1
  • 其他细节:
    • 考虑到精度问题,向上取整操作ceil()有可能会得到错误答案,常见的做法是减去一个误差值eps之后再向上取整
  • 参考资料:官方题解
class Solution {
private:
    const double INF = 1e10;
    const double eps = 1e-8;
    int n;
    vector<vector<double>> dp;
    
public:
    int minSkips(vector<int>& dist, int speed, int hoursBefore) {
        n = dist.size();
        dp.resize(n + 1, vector<double>(n + 1, INF));
        dp[0][0] = 0;
        for(int i = 1; i <= n; ++i) {
            for(int j = 0; j <= i; ++j) {
                dp[i][j] = min(dp[i][j], ceil(dp[i - 1][j] + (double)dist[i - 1] / speed - eps));
                if(0 < j) {
                    dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + (double)dist[i - 1] / speed);
                }
            }
        }
        for(int i = 0; i <= n; ++i) {
            if(dp[n][i] <= hoursBefore) {
                return i;
            }
        }
        return -1;
    }
};
原文地址:https://www.cnblogs.com/linrj/p/14830735.html