zoukankan      html  css  js  c++  java
  • 单周赛 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) 的一个子数组,请计算子数组的差绝对值最小值

    数据规定

    (2leq nleq 10^5)

    (1leq nums[i]leq 100)

    (1leq qleq 2cdot 10^4)

    题解

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

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

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

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

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

    时间复杂度 (O(100cdot (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;
        }
    };
    
  • 相关阅读:
    冒泡排序
    二分查找
    数3退1的java实现
    列出目录下对应的子目录及文件
    errno相关
    Fibonacci
    windows 下查看Python 的安装路径
    20条编程经验
    [转]一位程序员工作10年总结的13个忠告
    Sql查询语句过滤重复的数据
  • 原文地址:https://www.cnblogs.com/ChenyangXu/p/15059224.html
Copyright © 2011-2022 走看看