leetcode第 343 场周赛

这篇文章包含四个编程问题的解决方案:A题是关于保龄球游戏的胜利者判定,主要涉及得分计算;B题涉及矩阵中的叠涂元素,重点在于行和列的计数;C题使用Dijkstra算法寻找最小代价路径;D题是生成字典序最小的美丽字符串,需要避免特定长度的回文子串。
摘要由CSDN通过智能技术生成

A 保龄球游戏的获胜者

在这里插入图片描述
模拟

class Solution {
public:
    int isWinner(vector<int> &a1, vector<int> &a2) {
        int n = a1.size();
        int s1 = a1[0], s2 = a2[0];
        if (n != 1) {
            s1 += a1[0] == 10 ? 2 * a1[1] : a1[1];
            s2 += a2[0] == 10 ? 2 * a2[1] : a2[1];
        }
        for (int i = 2; i < n; i++) {
            s1 += max(a1[i - 2], a1[i - 1]) == 10 ? 2 * a1[i] : a1[i];
            s2 += max(a2[i - 2], a2[i - 1]) == 10 ? 2 * a2[i] : a2[i];
        }
        if (s1 > s2)
            return 1;
        else if (s1 < s2)
            return 2;
        return 0;
    }
};

B 找出叠涂元素

在这里插入图片描述
模拟:记录各行各列已有元素数

class Solution {
public:
    int firstCompleteIndex(vector<int> &a, vector<vector<int>> &g) {
        int len = a.size(), m = g.size(), n = g[0].size();
        vector<pair<int, int>> li(len);
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++) {
                li[g[i][j] - 1] = {i, j};
            }
        vector<int> cnt_row(m), cnt_col(n);
        int res;
        for (int i = 0; i < len; i++) {
            if (++cnt_row[li[a[i] - 1].first] == n) {
                res = i;
                break;
            }
            if (++cnt_col[li[a[i] - 1].second] == m) {
                res = i;
                break;
            }
        }
        return res;
    }
};

C 前往目标的最小代价

在这里插入图片描述

dijkstra:先建图用n*2+2个点存储所有边的端点、起点和终点,然后建边,之后从起点跑dijkstra

class Solution {
public:
    inline int get_dis(pair<int, int> &a, pair<int, int> &b) {
        return abs(a.first - b.first) + abs(a.second - b.second);
    }

    int minimumCost(vector<int> &start, vector<int> &target, vector<vector<int>> &e) {
        int n = e.size();
        int m = n * 2 + 2;
        vector<pair<int, int>> a(m);
        vector<pair<int, int>> edge[m];
        for (int i = 0; i < n; i++) {
            a[i * 2] = {e[i][0], e[i][1]};
            a[i * 2 + 1] = {e[i][2], e[i][3]};
        }
        a[n * 2] = {start[0], start[1]};//起点
        a[n * 2 + 1] = {target[0], target[1]};//终点
        for (int i = 0; i < n; i++) {
            edge[i * 2].emplace_back(i * 2 + 1, e[i][4]);
            for (int j = 0; j < m; j++) {//建边
                if (j != i * 2)
                    edge[i * 2].emplace_back(j, get_dis(a[j], a[i * 2]));
                if (j != i * 2 + 1)
                    edge[i * 2 + 1].emplace_back(j, get_dis(a[j], a[i * 2 + 1]));
            }

        }
        for (int j = 0; j < m; j++)//建边
            if (j != n * 2)
                edge[n * 2].emplace_back(j, get_dis(a[j], a[n * 2]));
        vector<int> vis(m);
        long long inf = 1e10;
        vector<long long> d(m, inf);
        d[n * 2] = 0;
        int tar = n * 2 + 1;
        while (1) {
            long long mn = inf, cur;
            for (int i = 0; i < m; i++) {
                if (!vis[i] && d[i] < mn) {
                    mn = d[i];
                    cur = i;
                }
            }
            vis[cur] = 1;
            if (cur == tar)
                break;
            for (auto [j, c]: edge[cur]) {
                if (!vis[j] && d[cur] + c < d[j])
                    d[j] = d[cur] + c;
            }
        }
        return d[tar];
    }
};

D 字典序最小的美丽字符串

在这里插入图片描述

脑筋急转弯:任意s[i]若s[i]!=s[i-1]&&s[i]!=s[i-2],则s满足不包含任何长度>1的回文子字符串,所以可以对s从后往前枚举每一位,判断当前位是否可以满足条件地变大,找到这样的位置将其变大,并将其右边最小化(同时用s[i]!=s[i-1]&&s[i]!=s[i-2]保证不存在长>1的回文串),因为题目k>=4,所以将其右边最小化采用按位枚举一定有解

class Solution {
public:
    string smallestBeautifulString(string s, int k) {
        int n = s.size();
        int i = n - 1;
        int j;
        while (i >= 0) {//找到最右边可以满足条件地变大的位置
            int can = 0;
            for (j = s[i] + 1; j - 'a' < k; j++) {
                if ((i - 1 < 0 || j != s[i - 1]) && (i - 2 < 0 || j != s[i - 2])) {
                    can = 1;
                    break;
                }
            }
            if (can)
                break;
            i--;
        }
        if (i == -1)
            return "";
        s[i] = j;
        for (i = i + 1; i < n; i++) {//右边最小化
            for (j = 'a'; j - 'a' < k; j++) {
                if ((i - 1 < 0 || j != s[i - 1]) && (i - 2 < 0 || j != s[i - 2])) {
                    s[i] = j;
                    break;
                }
            }
        }
        return s;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值