LeetCode第284场周赛

2022.3.13LeetCode第284场周赛

2200. 找出数组中的所有 K 近邻下标

思路

二分:找出nums中所有值为key的下标,对于每个元素,寻找前后两个最近的下标,若其中一个小于等于k,则该元素满足条件

代码

class Solution {
public:
    vector<int> findKDistantIndices(vector<int>& nums, int key, int k) {
        int n = nums.size();
        vector<int> ans;
        vector<int> b;
        for (int i = 0; i < n; i ++ ) {
            if (nums[i] == key)
                b.push_back(i);
        }
        for (int i = 0; i < n; i ++ ) {
            int t = lower_bound(b.begin(), b.end(), i) - b.begin();
            int res = 1e9;
            if (t < b.size())
                res = b[t] - i;
            if (t > 0)
                res = min(res, i - b[t - 1]);
            if (res <= k)
                ans.push_back(i);
        }
        return ans;
    }
};

2201. 统计可以提取的工件

思路

模拟+哈希:将所有要挖的单元格存储下来,枚举所有工件判断是否能被提取出来

代码

class Solution {
public:
    int digArtifacts(int n, vector<vector<int>>& artifacts, vector<vector<int>>& dig) {
        set<pair<int, int>> se;
        for (auto i : dig) {
            se.insert({i[0], i[1]});
        }
        int ans = 0;
        for (auto i : artifacts) {
            int r1 = i[0], c1 = i[1], r2 = i[2], c2 = i[3];
            bool f = true;
            for (int i = r1; i <= r2 && f; i ++ )
                for (int j = c1; j <= c2; j ++ ) {
                    if (!se.count({i, j})) {
                        f = false;
                        break;
                    }
                }
            if (f)
                ans ++ ;
        }
        return ans;
    }
};

2202. K 次操作后最大化顶端元素

思路

分类讨论

  1. nums的大小为1时,每步操作只有一种选择,k为偶数时,栈里存在1个元素;k为奇数时,栈中没有元素
  2. nums的大小大于1时,栈顶元素可能存在以下情况:
    • nums的前k - 1个元素的最大值 (取出前k个数,再放回最大值)
    • nums的第k + 1个元素(取出前k个数)

代码

class Solution {
public:
    int maximumTop(vector<int>& nums, int k) {
        int n = nums.size();
        if (n == 1 && k % 2) return -1;
        int ans = 0;
        for (int i = 0; i + 1 < k && i < n; i ++ )
            ans = max(ans, nums[i]);
        if (k < n)
            ans = max(ans, nums[k]);
        return ans;
    }
};

2203. 得到要求路径的最小带权子图

思路

堆优化的dijkstra+枚举中间节点
所有从src1src2dest的子图,一定包含某一中间节点x,所包含的路径为从src1xsrc2x,和xdest。在图中作三次dijkstra最短路,其中x在反图中求,再枚举所有x求边权和的最小值
证明:若最优解中src1destsrc2dest两条路径的第一个交点是x,则一起从xdest是最优的,否则其他路径的边权和一定大于最短路的边权和

代码

typedef long long ll;
typedef pair<ll, int> PLI;
class Solution {
public:
    vector<vector<pair<int, int>>> g;
    vector<vector<pair<int, int>>> ug;
    int n;
    
    vector<ll> di(int s, vector<vector<pair<int, int>>> g) {
        vector<ll> d(n, 1e18);
        vector<bool> st(n, false);
        priority_queue<PLI, vector<PLI>, greater<PLI>> heap;
        d[s] = 0;
        heap.push({0, s});
        while (heap.size()) {
            auto t = heap.top();
            heap.pop();
            int v = t.second;
            ll dis = t.first;
            if (st[v]) continue;
            st[v] = true;
            for (auto i : g[v]) {
                int j = i.first, w = i.second;
                if (d[j] > dis + w) {
                    d[j] = dis + w;
                    heap.push({d[j], j});
                }
            }
        }
        return d;
    }
    
    long long minimumWeight(int _n, vector<vector<int>>& edges, int src1, int src2, int dest) {
        n = _n + 1;
        g.resize(n);
        ug.resize(n);
        
        for (auto i : edges) {
            g[i[0]].push_back({i[1], i[2]});
        }
        for (auto i : edges) {
            ug[i[1]].push_back({i[0], i[2]});
        }
        vector<ll> d1, d2, d3;
        d1 = di(src1, g);
        d2 = di(src2, g);
        d3 = di(dest, ug);
        ll ans = 1e18;
        for (int i = 0; i < n; i ++ ) {
            if (d1[i] != 1e18 && d2[i] != 1e18 && d3[i] != 1e18)
                ans = min(ans, d1[i] + d2[i] + d3[i]);
        }
        return ans == 1e18 ? -1 : ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值