《小R的并集大小期望计算》和《小R的排列挑战》| 豆包MarsCode AI刷题

116 阅读4分钟

今天我们将在豆包MarsCode AI刷题平台上,完成《小R的并集大小期望计算》与《小R的排列挑战》这两个算法问题,通过这些练习提升用户解决此类问题的能力

《小R的并集大小期望计算》题面如下:

图片.png

问题理解

要求计算随机选择两个集合的并集大小的期望值。每个集合中的元素都是唯一的且互不相同。

数据结构选择

通过 map<int, int> 来记录每个元素出现的次数。

算法步骤

  1. 统计元素出现次数

    • 遍历所有集合,将每个元素及其出现次数记录在 map<int, int> 中。
  2. 计算期望值

    • 对于每个元素,计算它在两个集合中同时出现的概率。

    • 具体来说,如果一个元素在 notnull 个集合中出现,在 null 个集合中不出现,那么它出现在两个集合的并集中的概率是:

      • 在两个不同集合中出现的概率:(notnull * null) / (n * (n - 1) / 2)
      • 在同一个集合中出现的概率:(notnull * (notnull - 1) / 2) / (n * (n - 1) / 2)
    • 将所有元素的概率加起来,得到期望值。

  3. 格式化输出

    • 使用 ostringstream 将期望值格式化为保留两位小数的字符串。

具体实现

#include <bits/stdc++.h>

using namespace std;

string solution(int n, vector<vector<int>> st) {
    // write code here
    // 统计每个元素出现的次数
    map<int,int> allNums;
    for(auto& x : st){
        for(int y : x){
            allNums[y]++;
        }
    }
    // 计算期望值
    double ret=0;
    for(auto& x : allNums){
        int notnull = x.second, null = n - notnull;
        ret += (notnull * null + notnull * (notnull - 1) / 2.0) / (n * (n - 1) / 2.0);
    }
    // 保留两位小数并转换为字符串
    ostringstream oss;
    oss << fixed << setprecision(2) << ret;
    return oss.str();
}

int main() {
    cout << fixed << setprecision(2) << (solution(2, {{1, 2}, {1, 3, 5}}) == "4.00") << endl;
    cout << fixed << setprecision(2) << (solution(3, {{1, 4}, {2, 5}, {3, 6, 7}}) == "4.67") << endl;
    cout << fixed << setprecision(2) << (solution(2, {{10, 20, 30}, {10, 30, 50, 70}}) == "5.00") << endl;
    return 0;
}
  • 时间复杂度O(n * m + k)
  • 空间复杂度O(k)

其中 n 是集合的数量,m 是每个集合的平均大小,k 是所有集合中不同元素的总数。

《小R的排列挑战》题面如下:

图片.png

问题理解

题目要求对一个长度为 n 的排列进行排序,但只能交换位置下标奇偶性相同的元素。目标是计算出最少的交换次数,使数组变成升序排列。如果无法通过这种交换方式使数组有序,则输出 -1

数据结构选择

在原数组 a 上操作,并使用另一个数组 allpos 来记录每个元素的当前位置。

算法步骤

  1. 初始化位置数组

    • 使用 allPos 数组记录每个元素在 a 中的当前位置。allPos[i] 表示元素 ia 中的位置。
  2. 遍历数组

    • 由左到右遍历数组 a,检查每个元素是否在其正确的位置上(即 a[i] 是否等于 i+1)。
  3. 检查和交换

    • 如果 a[i] 不在正确的位置上,查找 i+1 的位置 pos
    • 检查 posi 的奇偶性是否相同。如果不同,则无法通过题目要求的交换方式使数组有序,返回 -1
    • 如果奇偶性相同,则进行交换,并更新 allPos 数组中的位置信息,同时增加交换次数 ret
  4. 返回结果

    • 遍历结束后,返回交换次数 ret

具体实现

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int solution(int n, vector<int>& a) {
    int ret = 0;
    vector<int> allPos(n + 1, -1);
    
    // 初始化位置数组
    for (int i = 0; i < n; i++) {
        allPos[a[i]] = i;
    }
    
    // 遍历数组
    for (int i = 0; i < n; i++) {
        if (a[i] != i + 1) {
            int pos = allPos[i + 1];
            
            // 检查奇偶性
            if (pos % 2 != i % 2) {
                return -1;
            } else {
                // 交换元素
                ret++;
                allPos[a[i]] = pos;
                allPos[i + 1] = i;
                swap(a[i], a[pos]);
            }
        }
    }
    
    return ret;
}

int main() {
    vector<int> a1 = {1, 4, 5, 2, 3};
    cout << (solution(5, a1) == 2) << endl;

    vector<int> a2 = {4, 3, 2, 1};
    cout << (solution(4, a2) == -1) << endl;

    vector<int> a3 = {2, 4, 6, 1, 3, 5};
    cout << (solution(6, a3) == -1) << endl;
}

借助豆包MarsCode AI刷题平台,我们不仅高效地解决了《小R的并集大小期望计算》和《小R的排列挑战》,还加深了对相关算法和数据结构的理解,后续会借助豆包MarsCode AI给大家展示更多题目的解法。