第 88 场双周赛

55 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

6212. 删除字符使频率相同

给你一个下标从 0 开始的字符串 word ,字符串只包含小写英文字母。你需要选择 一个 下标并 删除 下标处的字符,使得 word 中剩余每个字母出现 频率 相同。

如果删除一个字母后,word 中剩余所有字母的出现频率都相同,那么返回 true ,否则返回 false 。

注意:

字母 x 的 频率 是这个字母在字符串中出现的次数。 你 必须 恰好删除一个字母,不能一个字母都不删除。  

示例 1:

输入:word = "abcc"
输出:true
解释:选择下标 3 并删除该字母,word 变成 "abc" 且每个字母出现频率都为 1

示例 2:

输入:word = "aazz"
输出:false
解释:我们必须删除一个字母,所以要么 "a" 的频率变为 1"z" 的频率为 2 ,要么两个字母频率反过来。所以不可能让剩余所有字母出现频率相同。

提示:

  • 2 <= word.length <= 100
  • word 只包含小写英文字母。
思路

数据范围只有100! 直接枚举即可,若是数据范围大一点,可能还需要思考一下

代码

class Solution {
public:
    bool equalFrequency(string word) {
        for (int i = 0; i < word.size(); i ++) {
            map<char, int> mp;
            for (int j = 0; j < word.size(); j ++) {
                if (i == j) continue;
                mp[word[j]] ++;
            }
            map<int, int> cnt;
            for (auto v : mp) cnt[v.second] ++;
            if (cnt.size() == 1) return true;
        }
        return false;
    }
};

6197. 最长上传前缀

给你一个 n 个视频的上传序列,每个视频编号为 1 到 n 之间的 不同 数字,你需要依次将这些视频上传到服务器。请你实现一个数据结构,在上传的过程中计算 最长上传前缀 。

如果 闭区间 1 到 i 之间的视频全部都已经被上传到服务器,那么我们称 i 是上传前缀。最长上传前缀指的是符合定义的 i 中的 最大值 。

请你实现 LUPrefix 类:

LUPrefix(int n) 初始化一个 n 个视频的流对象。 void upload(int video) 上传 video 到服务器。 int longest() 返回上述定义的 最长上传前缀 的长度。   示例 1:

输入:
["LUPrefix", "upload", "longest", "upload", "longest", "upload", "longest"]
[[4], [3], [], [1], [], [2], []]
输出:
[null, null, 0, null, 1, null, 3]

解释:
LUPrefix server = new LUPrefix(4);   // 初始化 4个视频的上传流
server.upload(3);                    // 上传视频 3 。
server.longest();                    // 由于视频 1 还没有被上传,最长上传前缀是 0 。
server.upload(1);                    // 上传视频 1 。
server.longest();                    // 前缀 [1] 是最长上传前缀,所以我们返回 1 。
server.upload(2);                    // 上传视频 2 。
server.longest();                    // 前缀 [1,2,3] 是最长上传前缀,所以我们返回 3 。

提示:

1 <= n <= 105
1 <= video <= 105
video 中所有值 互不相同 。
upload 和 longest 总调用 次数至多不超过 2 * 105 次。
至少会调用 longest 一次。
思路

没什么好考虑的。 直接记录当前最大值即可

代码

class LUPrefix {
public:
    int cnt = 0;
    vector<int> ve;
    LUPrefix(int n):ve(n + 100, 0) {
    }
    void flesh() {
        while (cnt < ve.size() && ve[cnt + 1]) cnt ++;
    }
    void upload(int video) {
        ve[video] = 1;
        flesh();
    }
    
    int longest() {
        return cnt;
    }
};

6213. 所有数对的异或和

给你两个下标从 0 开始的数组 nums1 和 nums2 ,两个数组都只包含非负整数。请你求出另外一个数组 nums3 ,包含 nums1 和 nums2 中 所有数对 的异或和(nums1 中每个整数都跟 nums2 中每个整数 恰好 匹配一次)。

请你返回 nums3 中所有整数的 异或和 。

 

示例 1:

输入:nums1 = [2,1,3], nums2 = [10,2,5,0]
输出:13
解释:
一个可能的 nums3 数组是 [8,0,7,2,11,3,4,1,9,1,6,3] 。
所有这些数字的异或和是 13 ,所以我们返回 13

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:0
解释:
所有数对异或和的结果分别为 nums1[0] ^ nums2[0] ,nums1[0] ^ nums2[1] ,nums1[1] ^ nums2[0] 和 nums1[1] ^ nums2[1] 。
所以,一个可能的 nums3 数组是 [2,5,1,6] 。
2 ^ 5 ^ 1 ^ 6 = 0 ,所以我们返回 0

 

提示:

1 <= nums1.length, nums2.length <= 105
0 <= nums1[i], nums2[j] <= 109
思路

所有的异或和
观察一下就可以发现是这个样子的
对于 [a, b, c] [d, e, f]
有 a^d^a^e^a^f....
异或可以交换顺序 所以,我们关注的应该是每个元素出现的次数

代码

class Solution {
public:
    int xorAllNums(vector<int>& nums1, vector<int>& nums2) {
        int ans = 0;
        if (nums1.size() % 2)
            for (auto v : nums2) ans ^= v;
        if (nums2.size() % 2)
            for (auto v : nums1) ans ^= v;
        return ans;
    }
};

6198. 满足不等式的数对数目

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,两个数组的大小都为 n ,同时给你一个整数 diff ,统计满足以下条件的 数对 (i, j) :

0 <= i < j <= n - 1 且 nums1[i] - nums1[j] <= nums2[i] - nums2[j] + diff. 请你返回满足条件的 数对数目 。

 

示例 1:

输入:nums1 = [3,2,5], nums2 = [2,2,1], diff = 1
输出:3
解释:
总共有 3 个满足条件的数对:
1. i = 0, j = 13 - 2 <= 2 - 2 + 1 。因为 i < j 且 1 <= 1 ,这个数对满足条件。
2. i = 0, j = 23 - 5 <= 2 - 1 + 1 。因为 i < j 且 -2 <= 2 ,这个数对满足条件。
3. i = 1, j = 22 - 5 <= 2 - 1 + 1 。因为 i < j 且 -3 <= 2 ,这个数对满足条件。
所以,我们返回 3

示例 2:

输入:nums1 = [3,-1], nums2 = [-2,2], diff = -1
输出:0
解释:
没有满足条件的任何数对,所以我们返回 0

 

提示:

n == nums1.length == nums2.length
2 <= n <= 105
-104 <= nums1[i], nums2[i] <= 104
-104 <= diff <= 104
思路

做法:树状数组

首先,我们将算式变一下形:

nums1[i]nums1[j]<=nums2[i]nums2[j]+diffnums1[i]nums2[i]<=nums1[j]nums2[j]+diffnums1[i]nums2[i]diff<=nums1[j]nums2[j]x[i]=nums1[i]nums2[i]x[i]diff<=x[j] nums1[i] - nums1[j] <= nums2[i] - nums2[j] + diff \\ nums1[i] - nums2[i] <= nums1[j] - nums2[j] + diff \\ nums1[i] - nums2[i] - diff <= nums1[j] - nums2[j] \\ 设 x[i] = nums1[i] - nums2[i] \\ 有 x[i] - diff <= x[j]

现在,我们只需要求出每一个数,从 他到最后有多少个数是大于当前这个 x[i]diffx[i] - diff的就是了

对于这一点,我们可以用树状数组来动态的维护!

代码

class Solution {
public:
    static const int N = 1e5 + 111;
    const int POS = 5e4;
    int tr[N];
    int low(int x) {return x & (-x);}
    void add(int x) {
        for (int i = x; i < N; i += low(i)) tr[i] += 1;
    }
    int query(int x) {
        int res = 0;
        for (int i = x; i; i -= low(i)) res += tr[i];
        return res;
    }
    long long numberOfPairs(vector<int>& nums1, vector<int>& nums2, int diff) {
        int n = nums1.size();
        long long ans = 0;
        vector<int> ve(n);
        for (int i = 0; i < n; i ++) ve[i] = nums1[i] - nums2[i];
        for (int i = n-1; i >= 0; i --) {
            ans += query(N-1) - query(ve[i] + POS - diff-1);
            add(ve[i] + POS);
        }
        return ans;
    }
};