10.16 腾讯笔试题解

10.16 腾讯笔试

心得:笔试题虽然看起来多了一点,但是每道题其实并不是很困难,掌握方法很快就能 AK

T1 链表结点的异或

模拟就行,注意一个是正向一个是反向

/**
 * struct ListNode {
 *    int val;
 *    struct ListNode *next;
 *    ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param a ListNode类 
     * @param b ListNode类 
     * @return ListNode类
     */
    ListNode* xorList(ListNode* a, ListNode* b) {
        // write code here
        vector<int> arr;
        vector<int> ans;
        while (a) {
            arr.push_back(a->val);
            a = a->next;
        }
        reverse(arr.begin(), arr.end());
        int i = 0;
        while (b && i < arr.size()) {
            ans.push_back(arr[i]^b->val);
            b = b->next; ++i;
        }
        while (b) {
            ans.push_back(b->val);
            b = b->next;
        }
        while (i < arr.size()) {
            ans.push_back(arr[i++]);
        }
        ListNode* hd = new ListNode(0);
        ListNode* p = hd;
        for (auto it = ans.rbegin(); it != ans.rend(); ++it) {
            p->next = new ListNode(*it);
            p = p->next;
        }
        while (hd->next && hd->next->val == 0) hd = hd->next;
        if (hd->next == 0) {
            return new ListNode(0);
        }
        return hd->next;
    }
};

T2 修改 K 次数组求最小值

我们只需要贪心的修改每次贡献最大的一个元素就行。由于 K 的范围很小,用优先级队列搞定。

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> arr(n);
    for (auto& e : arr) cin >> e;
    priority_queue<pair<int, int>> pq;
    for (int i = 0; i < n; ++i) {
        pq.emplace(arr[i] - __builtin_popcount(arr[i]), __builtin_popcount(arr[i]));
    }
    ll ans = 0;
    for (auto e : arr) ans += e;
    while (k--) {
        auto top = pq.top(); pq.pop();
        ans -= top.first;
        pq.emplace(top.second - __builtin_popcount(top.second), __builtin_popcount(top.second));
    }
    cout << ans << endl;
    return 0;
}

T3 队列模拟

由于数据的特殊性,[1, n] 的排列,因此我们直接贪心。

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

int main() {
    int n, e; cin >> n;
    deque<int> arr;
    for (int i = 0; i < n; ++i) {
        cin >> e;
        arr.push_back(e);
    }
    vector<int> ans;
    for (int i = 1; i <= n; ++i) {
        int p;
        if (i % 2) {
            if (arr.front() > arr.back()) {
                p = arr.front(); arr.pop_front();
            } else {
                p = arr.back(); arr.pop_back();
            }
        } else {
            if (arr.front() < arr.back()) {
                p = arr.front(); arr.pop_front();
            } else {
                p = arr.back(); arr.pop_back();
            }
        }
        ans.push_back(p);
    }
    for (auto e : ans) cout << e << " "; cout << endl;
    return 0;
}

T4 计算区间内 1 的个数

由于我们要求区间 内的 的个数,转化为求 的个数比较好。下面介绍如何求解 的个数。

,显然可以知道其中一半的位置都是 .

我们找到小于等于 最大的 ,有 ,对答案的贡献为:, 还剩下:

剩下的部分无非是前部分的反转,因此我们可以递归的求解 (),但是由于首位中 变为了 ,我们需要知道这一点。

当最后 时,如果我们记录的首位为 ,那么答案是 ,如果首位是 ,那么答案是

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

ll cal(ll num, int bit) {
    if (num == 0) return 0;
    else if (num == 1) return bit;
    else if (num == 2) return 1;
    ll x = 0;
    while ((1ll << x) <= num) ++x;
    --x;
    num -= (1ll<<x);
    ll ans = 0;
    if (x > 0) {
        ans += (1ll<< (x-1));
    }
    return ans + cal(num, 1-bit);
}

int main() {
    ll L, R; cin >> L >> R;
    cout << cal(R, 1) - cal(L-1, 1) << endl;
    return 0;
}

T5 构造数组

给一个数组 ,希望我们找到两个数 X,Y 使得:

  1. 生成, 或者 , 并且
  2. 并且 最小

值得注意的是, 因此如果我们希望 ,那么 X,Y一定是异号的,或者 X = 0 or Y = 0。我们暂时忽略后一种情况。不失一般性,我们假设 ,那么有

假定序列 是我们构造 时所选的下标,因此有:

因此,最后问题转化为找到一个 子序列,其和 ,并且有:

我们可以事先算出 所有的子序列构成的和,然后找到满足上式最小的一个。那么这样我们就顺利找到了所求的 。但是题目还要求这个子序列是如何选取的,这就是标准的背包问题,我们只需要套模板就行,下面给出代码:

#include <bits/stdc++.h>

using namespace std;
using ll = long long;
#define maxn 100005

int main() {
//     freopen("data.in", "r", stdin);
    int n; cin >> n;
    vector<int> arr(n);
    for (auto& e : arr) cin >> e;
    int sum = accumulate(arr.begin(), arr.end(), 0);
    unordered_set<int> ss;
    for (auto e : arr) {
        vector<int> newr;
        for (auto s : ss) {
            newr.push_back(s + e);
        }
        newr.push_back(e);
        for (auto e : newr) ss.insert(e);
    }
    int X = -1, Y = -1, d = INT_MAX;
    for (auto e : ss) {
        if (abs(sum - 2 *e) < d) {
            X = e, Y = e - sum;
            d = abs(sum - 2*e);
        }
    }
    // we should find the path
    vector<bool> f(maxn);
    vector<unordered_map<int, int>> last(n);
    f[0] = 1;
    for (int i = 0; i < n; ++i) {
        vector<bool> g = f;
        auto& e = arr[i];
        g[e] = 1;
        for (int j = 0; j < maxn; ++j) {
            if (f[j] && j + e < maxn) {
                g[j+e] = 1;
                last[i][j+e] = j;
            }
        }
        f = move(g);
    }
    if (!f[X]) cout << -1 << endl;
    else {
        int i = n-1, sum = X;
        vector<int> ans(n, 0);
        while (i >= 0) {
            if (last[i].count(sum)) {
                ans[i] = 1;
                sum = last[i][sum];
            }
            --i;
        }
        cout << X << " " << Y << endl;
        for (auto e : ans) if (e == 1) cout << "Y"; else cout << "X";
        cout << endl;
    }
    return 0;
}
#腾讯##笔试##腾讯笔试##秋招##算法题#
全部评论
我一道都不会啊
1 回复 分享
发布于 2022-10-16 22:31 浙江
第五题回溯加两次贪心优化也能过
1 回复 分享
发布于 2022-10-17 12:38 广东
最后一题不知道哪出问题了,xy算的是对的但是分组全错,寄
点赞 回复 分享
发布于 2022-10-16 23:02 湖北
猛,第五题想到是背包,但不知道怎么写
点赞 回复 分享
发布于 2022-10-17 11:39 福建
请问题目有链接吗
点赞 回复 分享
发布于 2022-10-17 11:57 四川
点赞 回复 分享
发布于 2022-10-17 16:41 云南

相关推荐

尊尼获获:闺蜜在哪?
点赞 评论 收藏
分享
菜菜咪:1. 可以使用简历网站的模版,美观度会更好一点 2. 邮箱可以重新申请一个,或者用qq邮箱的别名,部分hr可能会不喜欢数字邮箱 3. 项目经历最好分点描述,类似的项目很多,可以参考一下别人怎么写的 4. 自我评价可加可不加,技术岗更看重技术。最后,加油,优秀士兵
点赞 评论 收藏
分享
20 67 评论
分享
牛客网
牛客企业服务