【大厂笔试题】携程 2025.4.15

一、字符串相似性判断(去重比对)

首先将每个字符串中把每个字母去重(多次出现只保留最先出现的那个字母),若两个字符串一致,我们则认为两个字符串相似。游游会提出多此询问,请你帮助她判断两个字符串是否相似。输入描述每个测试文件均包含多组测试数。第一行输入一个整数 T(1 <= T <=1000),代表数据组数,每组测试数据描述如下:对于每一组测试数据:2 行,每行一个字符串。分别代表81和82,输入保证仅有小写字母组成且长度不超过 1 0 5 10^5 105。数据保证单个测试文件的所有字符串长度之和不超过 1 0 5 10^5 105输出描述对于每一组数据,若两个字符串相似,输出"YES",否则输出"NO"。

思路:用哈希集合记录首次出现的字符,构造去重后的字符串,比对两个处理后的字符串是否一致

#include 
using namespace std;

string dedup(const string& s) {
    unordered_set<char> seen;
    string res;
    for (char c : s) {
        if (!seen.count(c)) {
            seen.insert(c);
            res += c;
        }
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int T;
    cin >> T;
    while (T--) {
        string s1, s2;
        cin >> s1 >> s2;
        cout << (dedup(s1) == dedup(s2) ? "YES\n" : "NO\n");
    }
    return 0;
}
二、最大收益问题(贪心算法)

游游现在有一个公司,这个公司里有n个任务,每一个任务都有一个能力值和收益值,现在有m个工人,每一个工人都有一个能力值,对于每一个任务来说,只有这个人的能力值不低于该任务需要的能力值,才可以完成这个任务。假设多个工人可以完成,同一个任务,收益为这个任务的收益值乘以这个任务完成的次数,现在想知道每一个工人最多只能安排一个任务的前提下,最大的收益值是多少?输入描述每一个文件输入第一行输入一个整数T(1<=T<=100),代表有T组测试数据。接下来T组,每一组第一行输入两个整数n,m(1≤n,m≤ 1 0 4 10^4 104)第二行输入n个整数,其中ai代表第i个任务所需要的的能力值第三行输入n个整数,其中p[i](1 ≤ p[i]≤ 1 0 5 10^5 105)代表第i个任务的收益第四行输入m个整数,其中b[i](1 ≤ b[i]≤ 1 0 5 10^5 105)代表第i个工人的能力数据保证同一个文件内n的总和不超过 1 0 5 10^5 105,m的总和不超过 1 0 5 10^5 105数据保证同一个文件内n的总和不超过 1 0 5 10^5 105,m的总和不超过 1 0 5 10^5 105输出描述对于每一组测试数据,输出一个答案代表最大的收益。
思路:任务按能力排序,工人按能力排序,双指针+最大堆维护可用任务

#include 
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int T;
    cin >> T;
    while (T--) {
        int n, m;
        cin >> n >> m;
        
        vector<pair<int, int>> tasks(n);
        for (int i = 0; i < n; ++i) cin >> tasks[i].first;
        for (int i = 0; i < n; ++i) cin >> tasks[i].second;
        
        sort(tasks.begin(), tasks.end());
        
        vector<int> workers(m);
        for (int i = 0; i < m; ++i) cin >> workers[i];
        sort(workers.begin(), workers.end());
        
        priority_queue<int> pq;
        long long total = 0;
        int j = 0;
        
        for (int w : workers) {
            while (j < n && tasks[j].first <= w) {
                pq.push(tasks[j].second);
                j++;
            }
            if (!pq.empty()) {
                total += pq.top();
                pq.pop();
            }
        }
        cout << total << '\n';
    }
    return 0;
}
三、整数分解问题(数学公式)

游游给定了两个正整数n,m,他希望能将n分解为恰好m个连续(排好序后满足后一项等于前一项加一)非负整数,使得这些数的和是n,他想知道能否办到,请你帮帮他吧。连续的非负整数:即,如果将这些整数从小到大排好序后存入b数组,则第一项大于等于0,且对于任意i(1 1 0 4 10^4 104)代表数据组数,每组测试数据描还如下:在单独的一行输入两个空格分割的正整数n,m(1≤n≤ 1 0 1 8 10^18 1018;1≤m≦ 1 0 9 10^9 109),表示游游给定的正整数.输出描述对于每组测试数据:如果可以将 π 分解为m个满足题意的非负整数,则在单独的一行输出"YES",否则输出"NO"。
思路:等差数列求和公式变形,根据m的奇偶性判断整除条件

#include 
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int T;
    cin >> T;
    while (T--) {
        ll n, m;
        cin >> n >> m;
        
        if (2 * n % m != 0) {
            cout << "NO\n";
            continue;
        }
        
        ll q = 2 * n / m;
        bool valid = false;
        
        if (m % 2) { // m奇数
            valid = (q % 2 == 0) && (q > m);
        } else { // m偶数
            valid = (q % 2 == 1) && (q > m);
        }
        
        cout << (valid ? "YES\n" : "NO\n");
    }
    return 0;
}
四、最小覆盖圆问题(几何计算)

二维平面上有两个三角形△ABC 和 △DEF。求解最小半径的圆,使得完全覆盖这两个三角形。输入描述第一行输入六个整数xA,yA,xB,yB,xC,yC(-100≤xA,yA,xB,yB,xC,yC≤100)代表△ABC的三个顶点。保证三角形存在。第二行输入六个整数xD,yD,xE,yE,xF,yF(一100≤xD,yD,xE,yE,xF,yF≤100)代表△DEF的三个顶点。保证三角形存在。输出描述在一行上输出一个实数代表最小圆的半径。由于实数的计算存在误差,当误差的显级不超过 1 0 − 6 10^-6 106 时,您的答案都将被接受。具体来说,设您的答案为a,标准答案为b,当且仅当时,您的答案将被接受。
思路:枚举所有候选圆(两点直径圆、三点外接圆),取最小满足条件的半径

#include 

using namespace std;

struct Point { double x, y; };

const double EPS = 1e-8;

// 计算两点距离平方
double dist2(const Point& a, const Point& b) {
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}

// 三点外接圆
pair<Point, double> circumCircle(const Point& A, const Point& B, const Point& C) {
    double a1 = 2*(B.x - A.x), b1 = 2*(B.y - A.y);
    double c1 = B.x*B.x + B.y*B.y - A.x*A.x - A.y*A.y;
    double a2 = 2*(C.x - A.x), b2 = 2*(C.y - A.y);
    double c2 = C.x*C.x + C.y*C.y - A.x*A.x - A.y*A.y;
    
    double det = a1*b2 - a2*b1;
    if (fabs(det) < EPS) return {{0,0}, -1}; 
    
    Point center = {
        (b2*c1 - b1*c2)/det,
        (a1*c2 - a2*c1)/det
    };
    return {center, sqrt(dist2(center, A))};
}

bool checkCover(const Point& center, double r2, const vector<Point>& pts) {
    for (auto& p : pts) {
        double dx = p.x - center.x;
        double dy = p.y - center.y;
        if (dx*dx + dy*dy > r2 + EPS) return false;
    }
    return true;
}

double solve(const vector<Point>& points) {
    double min_r = 1e18;
    const int n = points.size();

    for (int i = 0; i < n; ++i) {
        for (int j = i+1; j < n; ++j) {
            Point center = {
                (points[i].x + points[j].x)/2,
                (points[i].y + points[j].y)/2
            };
            double r2 = dist2(points[i], center);
            if (checkCover(center, r2, points)) {
                min_r = min(min_r, sqrt(r2));
            }
        }
    }
    
    // 枚举三点组合
    for (int i = 0; i < n; ++i) {
        for (int j = i+1; j < n; ++j) {
            for (int k = j+1; k < n; ++k) {
                auto [center, r] = circumCircle(points[i], points[j], points[k]);
                if (r < 0) continue;
                if (checkCover(center, r*r, points)) {
                    min_r = min(min_r, r);
                }
            }
        }
    }
    
    return min_r;
}

int main() {
    vector<Point> points(6);
    for (int i = 0; i < 6; ++i) {
        if (i < 3) cin >> points[i].x >> points[i].y;
        else cin >> points[i+3].x >> points[i+3].y;
    }
    
    cout << fixed << setprecision(12) << solve(points) << endl;
    return 0;
}

你可能感兴趣的:(大厂面试题,c++)