第 238 场周赛

316 阅读2分钟

5738. K 进制表示下的各位数字总和

题目

给你一个整数 n10 进制)和一个基数 k ,请你将 n10 进制表示转换为 k 进制表示,计算并返回转换后各位数字的 总和

转换后,各位数字应当视作是 10 进制数字,且它们的总和也应当按 10 进制表示返回。

示例 1:

输入:n = 34, k = 6
输出:9
解释:34 (10 进制) 在 6 进制下表示为 54 。5 + 4 = 9

示例 2:

输入:n = 10, k = 10
输出:1
解释:n 本身就是 10 进制。 1 + 0 = 1

提示:

  • 1 <= n <= 100
  • 2 <= k <= 10

思路

直接模拟

代码

// 0 ms	5.6 MB
class Solution {
public:
    int sumBase(int n, int k) {
        int res = 0;
        while (n) {
            res += n % k;
            n /= k;
        }
        return res;
    }
};

5739. 最高频元素的频数

题目

元素的 频数 是该元素在一个数组中出现的次数。

给你一个整数数组 nums 和一个整数 k 。在一步操作中,你可以选择 nums 的一个下标,并将该下标对应元素的值增加 1

执行最多 k 次操作后,返回数组中最高频元素的 最大可能频数

示例 1:

输入:nums = [1,2,4], k = 5
输出:3
解释:对第一个元素执行 3 次递增操作,对第二个元素执 2 次递增操作,此时 nums = [4,4,4] 。
4 是数组中最高频元素,频数是 3 。

示例 2:

输入:nums = [1,4,8,13], k = 5
输出:2
解释:存在多种最优解决方案:
- 对第一个元素执行 3 次递增操作,此时 nums = [4,4,8,13] 。4 是数组中最高频元素,频数是 2 。
- 对第二个元素执行 4 次递增操作,此时 nums = [1,8,8,13] 。8 是数组中最高频元素,频数是 2 。
- 对第三个元素执行 5 次递增操作,此时 nums = [1,4,13,13] 。13 是数组中最高频元素,频数是 2

示例 3:

输入:nums = [3,9,6], k = 2
输出:1

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5
  • 1 <= k <= 10^5

思路

二分 + 前缀和

  • 二分最大频数,每次判断当前频数mid是否能被满足。

  • 由于每次只能对一个元素加1,所以对于给定的下标index,我们贪心地将[index - mid + 1, index]区间的所有元素都变为nums[index],这里通过提前维护前缀和没客源判断是否在不超过k次操作中完成该转换。

双指针 + 前缀和(滑动窗口)

思路和二分差不多,这里只不过使用滑动窗口来约束k的条件

代码

二分 + 前缀和代码

// 368 ms	84.1 MB
typedef long long ll;
class Solution {
public:
    int maxFrequency(vector<int>& nums, int k) {
        int res = 0;
        int n = nums.size();
        sort(nums.begin(), nums.end());
        
        vector<ll> sum(n + 1);
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1];
        
      	// 遍历所有的元素,找每个元素前面的值
        for (int i = 1; i <= n; i++) {
            // 每一个数作为右边界,二分找左边界
            int l = 1, r = i;
            while (l < r) {
                int mid = (l + r) / 2;
                // 如果在这个区间上[j, i],则一定有nums[i] * [i - j + 1] <= k 才能在使得这个区间所有的值变成nums[i];
                if ((nums[i - 1] * (ll)(i - mid + 1) - (sum[i] - sum[mid - 1])) <= k) r = mid;
                else l = mid + 1;
            }
            res = max(res, i - r + 1);
        }
        return res;
    }
};

双指针 + 前缀和(滑动窗口)代码

// 296 ms	84.1 MB
typedef long long ll;
class Solution {
public:
    int maxFrequency(vector<int>& nums, int k) {
        int res = 0;
        int n = nums.size();
        sort(nums.begin(), nums.end());
        
        vector<ll> sum(n + 1);
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1];
        
        for (int i = 1, j = 1; i <= n; i++) {
            // 当窗口里面的值不能满足 全部变为nums[i - 1]即窗口右端的值时,左指针右移动,使得满足能够全部变为窗口右端的值
            while ((i - j + 1ll) * nums[i - 1] - (sum[i] - sum[j - 1]) > k) j++; 
            res = max(res, i - j + 1);
        }
        return res;
    }
};

5740. 所有元音按顺序排布的最长子字符串

题目

当一个字符串满足如下条件时,我们称它是 美丽的

  • 所有 5 个英文元音字母('a''e''i''o''u')都必须 至少 出现一次。
  • 这些元音字母的顺序都必须按照 字典序 升序排布(也就是说所有的 'a' 都在 'e' 前面,所有的 'e' 都在 'i' 前面,以此类推)

比方说,字符串 "aeiou""aaaaaaeiiiioou" 都是 美丽的 ,但是 "uaeio""aeoiu""aaaeeeooo" 不是美丽的

给你一个只包含英文元音字母的字符串 word ,请你返回 word最长美丽子字符串的长度 。如果不存在这样的子字符串,请返回 0

子字符串 是字符串中一个连续的字符序列。

示例 1:

输入:word = "aeiaaioaaaaeiiiiouuuooaauuaeiu"
输出:13
解释:最长子字符串是 "aaaaeiiiiouuu" ,长度为 13

示例 2:

输入:word = "aeeeiiiioooauuuaeiou"
输出:5
解释:最长子字符串是 "aeiou" ,长度为 5

示例 3:

输入:word = "a"
输出:0
解释:没有美丽子字符串,所以返回 0 。

提示:

  • 1 <= word.length <= 5 * 10^5
  • word 只包含字符 'a''e''i''o''u'

思路

读懂题意之后直接使用队列或栈来模拟

代码

// 160 ms	42.1 MB
class Solution {
public:
    int longestBeautifulSubstring(string word) {
        int res = 0;
        queue<int> q;
        // 遍历所有的字符
        for (int i = 0; i < word.length(); i++) {
            int v;
            // 给字符自定义编号,按照上升序列来排列
            if (word[i] == 'a') v = 1;
            else if (word[i] == 'e') v = 2;
            else if (word[i] == 'i') v = 3;
            else if (word[i] == 'o') v = 4;
            else v = 5;
            // 如果队列非空,说明里面已经有数据了
            // 这时,需要判断最后一个队列里的 最后一个元素和即将入队的元素是否相等 或者成相邻升序的。
            // 满足条件才能入队列
            if (!q.empty()) {
                if (v == q.back() || v == q.back() + 1)  {
                    q.push(v);   
                }
                else {
                    // 不满足入队的条件
                    // 如果最后一个元素是‘u’,比较大小作为返回值
                    if (q.back() == 5)
                        res = max(res, (int)q.size());
                    // 并且需要清空队列
                    while (!q.empty()) 
                        q.pop();
                    // 再考虑刚刚需要入队的元素是否是‘a’是的话还需要讲刚刚的元素入队
                    if (v == 1) q.push(v);
                    else continue;
                     
                }
            } else {
                // 队列为空,判断第一个进来的元素是否是‘a’,满足才能入队
                if (v == 1) q.push(v);
                else continue;
            }
        }
        // 统计遍历完之后队列的元素
        if (!q.empty() && q.back() == 5)
            res = max(res, (int)q.size());
        return res;
    }
};

5741. 最高建筑高度

题目

在一座城市里,你需要建 n 栋新的建筑。这些新的建筑会从 1n 编号排成一列。

这座城市对这些新建筑有一些规定:

  • 每栋建筑的高度必须是一个非负整数。
  • 第一栋建筑的高度 必须0
  • 任意两栋相邻建筑的高度差 不能超过 1

除此以外,某些建筑还有额外的最高高度限制。这些限制会以二维整数数组 restrictions 的形式给出,其中 restrictions[i] = [idi, maxHeighti] ,表示建筑 idi 的高度 不能超过 maxHeighti

题目保证每栋建筑在 restrictions至多出现一次 ,同时建筑 1 不会 出现在 restrictions 中。

请你返回 最高 建筑能达到的 最高高度

示例 1:

img

输入:n = 5, restrictions = [[2,1],[4,1]]
输出:2
解释:上图中的绿色区域为每栋建筑被允许的最高高度。
我们可以使建筑高度分别为 [0,1,2,1,2] ,最高建筑的高度为 2

示例 2:

img

输入:n = 6, restrictions = []
输出:5
解释:上图中的绿色区域为每栋建筑被允许的最高高度。
我们可以使建筑高度分别为 [0,1,2,3,4,5] ,最高建筑的高度为 5 。

示例 3:

img

输入:n = 10, restrictions = [[5,3],[2,5],[7,4],[10,3]]
输出:5
解释:上图中的绿色区域为每栋建筑被允许的最高高度。
我们可以使建筑高度分别为 [0,1,2,3,3,4,4,5,4,3] ,最高建筑的高度为 5

提示:

  • 2 <= n <= 10^9
  • 0 <= restrictions.length <= min(n - 1, 10^5)
  • 2 <= idi <= n
  • idi唯一的
  • 0 <= maxHeighti <= 10^9

思路

这道题,比赛没写出来,思路来源于评论大佬

  • 由于n 在10 ^ 9 数量级,所以我们需要二分最大可能高度 mid,每次判断是否合法。
  • 由于高度限制数组中,可能出现互相限制的情况,例如对于restriction = [[2, 1], [3, 5]] 的情况,第二、三栋建筑相差一格,所以第三栋建筑最大高度只能为 2;针对这类情况,我们提前从左向右和从右向左遍历高度限制数组,根据可能出现的“互相限制”情况对数组进行更新。
  • 二分过程判断合法过程中,根据相邻的两个限制条件可以计算出这两栋建筑之间可以形成的最高建筑高度。特别地,最后一个限制条件的建筑可以向右一直增长到第 n 栋建筑。

代码

// 948 ms	99.8 MB
class Solution {
    using ll = long long;
public:
    int maxBuilding(int n, vector<vector<int>>& v) {
        v.push_back({1, 0});
        sort(v.begin(), v.end());
        int m = v.size();
        // 从左向右遍历一遍
        int k = 0, index = 0;
        while(k + 1 < m) {
            int a = v[index][0], x = v[index][1], b = v[k + 1][0], y = v[k + 1][1];
            if(y - x >= b - a) {
                v[k + 1][1] = x + b - a;
            } else {
                index = k + 1;
            }
            k++;
        }


        // 从右向左遍历一遍
        k = m - 1, index = m - 1;
        while(k >= 1) {
            int a = v[index][0], x = v[index][1], b = v[k - 1][0], y = v[k - 1][1];
            if(y - x >= a - b) {
                v[k - 1][1] = x + a - b;
            } else {
                index = k - 1;
            }
            k--;
        }


        // 二分最大高度
        ll l = 1, r = INT_MAX;
        while(l <= r) {
            ll mid = l + (r - l) / 2;

            bool ok = false;

            for(int i = 0; i < m - 1; i++) {
                ll a = v[i][0], x = v[i][1], b = v[i + 1][0], y = v[i + 1][1];
                if(mid * 2 <= y + x + b - a) {
                    ok = true;
                    break;
                }
            }

            if(mid - v[m - 1][1] <= n - v[m - 1][0]) {
                ok = true;
            }

            if(ok) {
               l = mid + 1; 
            } else {
                r = mid - 1;
            }
        }


        return r;
    }
};