单周赛 246 题解

本次周赛不难,随便水水就做完了,心情舒适

涉及知识点:小学数学,模拟,深度优先搜索,并差集,桶排序,高性能算法

字符串中的最大奇数

给定一个表示正整数的字符串 \(s\),输出字符串中的最大奇数子字符串,如果不存在奇数,返回空字符串

题解

奇数的个位一定是奇数,所以从后往前遍历字符串 \(s\),找到第一个奇数的位置即可,如果找不到,就意味着不存在奇数

class Solution {
public:
    string largestOddNumber(string num) {
        int pos = -1;
        for (int i = num.length() - 1; i >= 0; --i) {
            if ((num[i] - '0') % 2) {pos = i; break;}
        }
        if (pos == -1) return "";
        else return num.substr(0, pos + 1);
    }
};

你完成的完整对局数

一个小时中,有四个时间点会开始一场 \(15\) 分钟的完整对局,分别是 HH:00, HH:15, HH:30, HH:45

现在给定两个 HH:MM 格式的时间,分别表示开始时间和终止时间,计算完成的完整对局数

注意,如果终止时间的 HH 小于开始时间的 HH,说明玩了通宵,也就是说,玩到了第二天

题解

直接 if 特判多种情况

class Solution {
public:
    int t1(int x) {return x % 15 ? (x / 15 + 1) * 15 : x;}
    int t2(int x) {return x / 15 * 15;}
    int numberOfRounds(string st, string ft) {
        int h1 = (st[0] - '0') * 10 + st[1] - '0';
        int h2 = (ft[0] - '0') * 10 + ft[1] - '0';
        int m1 = (st[3] - '0') * 10 + st[4] - '0';
        int m2 = (ft[3] - '0') * 10 + ft[4] - '0';
        if (h2 < h1 || h2 == h1 && m2 < m1) h2 += 24;
        int ans = 0;
        if (h1 == h2) {
            ans += (4 + (t2(m2) - t1(m1) / 15)) % 4;
        }
        else if (m1 && m2) {
            ans += max(0, h2 - (h1 + 1)) * 4 + (60 - t1(m1)) / 15 + t2(m2) / 15;
        }
        else if (m1 && !m2) {
            ans += max(0, h2 - (h1 + 1)) * 4 + (60 - t1(m1)) / 15;
        }
        else if (!m1 && m2) {
            ans += max(0, h2 - h1) * 4 + t2(m2) / 15;    
        }
        else {
            ans += (h2 - h1) * 4;
        }
        return ans;
    }
};

统计子岛屿

给定长和宽一致的两个 \(01\) 矩阵,分别表示两个地图,正如你所猜想的那样,其中的 \(1\) 表示陆地,\(0\) 表示水域,岛屿就是连着的 \(1\) 组成的区域

对于矩阵 \(2\) 中的岛屿,如果他是矩阵 \(1\) 中岛屿的子区域,那么我们称之为子岛屿,现在要统计子岛屿的数量

题解

如果你做过统计岛屿,那就好办了

统计岛屿可以使用 dfs, bfs 等搜索办法来统计数量,也可以使用并查集来统计

这道题只需要在统计的过程中判断一下是否是子岛屿即可,确切的说,只需要检查在特定位置 \(i,\ j\),两个矩阵是否同时为 \(1\) 即可

  • 一旦不为 \(1\),那一定不是子岛屿
  • 如果为 \(1\),还要继续判断

具体的实现,我是通过在 dfs 的过程中维护一个引用的 \(flag\) 变量来判断的,不排除有其他方法

const int DX[] = {0, 1, 0, -1};
const int DY[] = {1, 0, -1, 0};
class Solution {
public:
    bool check(int x, int y, int m, int n)
    {
        return x >= 0 && x < m && y >= 0 && y < n;
    }
    void dfs(int x, int y, vector<vector<int>>& vis, vector<vector<int>>& grid1, vector<vector<int>>& grid2, int& flag) {
        int m = grid2.size();
        int n = grid2[0].size();
        vis[x][y] = 1;
        if (grid1[x][y] != 1) flag = 0;
        for (int i = 0; i < 4; ++i) {
            int tx = x + DX[i], ty = y + DY[i];
            if (check(tx, ty, m, n) && !vis[tx][ty] && grid2[tx][ty] == 1) {
                if (grid1[tx][ty] != 1) {
                    flag = 0;
                }
                dfs(tx, ty, vis, grid1, grid2, flag);
            }
        }
    }
    int countSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2) {
        int m = grid2.size();
        int n = grid2[0].size();
        vector<vector<int>> vis(m, vector<int>(n));
        int ans = 0;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (!vis[i][j] && grid2[i][j] == 1) {
                    int flag = 1;
                    dfs(i, j, vis, grid1, grid2, flag);
                    if (flag) {
                        //cout << i << ' ' << j << endl;
                        ans++;
                    }
                }
            }
        }
        return ans;
    }
};

查询差绝对值的最小值

对于一个数组,我们定义差绝对值的最小值为 数组中两个元素做差的绝对值的最小值

例如 [5,2,3,7,2] 的差绝对值最小值为 |3 - 2| = 1

如果元素一样,例如 [2,2,2],那么差绝对值为 -1

是的,我们不考虑相同值的元素做差的情况,也就是说,差绝对值最小值一定不可能是 0

现在给定长为 \(n\) 的数组 \(nums\),以及 \(q\) 个询问,每次询问 \(nums\) 的一个子数组,请计算子数组的差绝对值最小值

数据规定

\(2\leq n\leq 10^5\)

\(1\leq nums[i]\leq 100\)

\(1\leq q\leq 2\cdot 10^4\)

题解

为了计算数组的差绝对值最小值,我们无可避免的需要遍历所有元素

为了一次遍历,还需要维护数组有序,这样才能保证相邻元素做差可能出现最小值,但是这样需要 \(O(nlogn + n)\) 的时间来计算,代价太高

注意到 \(nums[i]\leq 100\),考虑用桶来优化,用桶的好处在于,桶排序的思想自动维护了数组有序,并且遍历的代价也不高,为 \(O(100)\)

具体来说,预处理 \(1\sim 100\) 内各个数字在每个位置 \(i\) 出现次数的前缀和,这样我们在查询 \([L,\ R]\) 区间时,就可以通过差分快速判断某个数字是否出现过

查询的时候,把所有出现过的数字放入临时数组,遍历计算相邻数字的差来维护差绝对值的最小值,特别的,如果最大值等于最小值,返回 \(-1\)

时间复杂度 \(O(100\cdot (n+ q))\)

class Solution {
public:
    vector<int> minDifference(vector<int>& n, vector<vector<int>>& q) {
        vector<vector<int>> b(n.size() + 1, vector<int>(101));
        for (int i = 1; i <= n.size(); ++i) {
            b[i][n[i - 1]]++;
            for (int j = 1; j <= 100; ++j) {
                b[i][j] += b[i - 1][j];
            }
        }
        vector<int> ans;
        for (auto &i: q) {
            int L = i[0] + 1, R = i[1] + 1;
            vector<pair<int, int>> B;
            for (int j = 1; j <= 100; ++j) {
                int cnt = b[R][j] - b[L - 1][j]; // j 出现的次数
                if (cnt > 0) B.push_back(pair<int, int> {j, cnt});
            }
            int pos = 0, temp = 101;
            for (int j = 0; j < B.size() - 1; ++j) {
                pair<int, int> x = B[j], y = B[j + 1];
                temp = min(temp, y.first - x.first);
            }
            if (B[0].first == B[B.size() - 1].first) temp = -1;
            ans.push_back(temp);
        }
        return ans;
    }
};
posted @ 2021-07-25 22:11  徐摆渡  阅读(35)  评论(0编辑  收藏  举报