淘天笔试 淘天笔试题 0816

笔试时间:2025年8月16日

往年笔试合集:

2023春招秋招笔试合集

2024春招秋招笔试合集

第一题:混乱的数字

给定一个长度为 ( n ) 的数组 ({a_1, a_2, \ldots, a_n}),数组中的元素互不相同。我们希望最后能够按严格从大到小的顺序将所有元素输出。为此,我们决定使用若干个队列来对元素进行整理,每一个队列都是先进先出(FIFO)的结构。整个过程分为两个阶段:

分配阶段:按照数组的原始顺序(从 ( i = 1 ) 到 ( n )),选择任意一个队列将 ( a_i ) 放入。然而,如果队列中已经存在元素,则只能将 ( a_i ) 放入与队列中已有元素相同奇偶性的队列中。

输出阶段:当所有元素都分配完毕后,开始输出。每一步,选择任意一个队列,取出其头部的元素并输出。目标是在整个输出过程中得到一个严格递减的序列。

显然,如果不限制队列的数量,那么可以轻松的完成任务。所以,你需要求解,至少需要多少个队列,才能完成上述流程并保证最终输出严格递减。

输入描述

第一行输入一个整数 ( n )((1 \le n \le 2 \times 10^5)),表示数组的长度。

第二行输入 ( n ) 个整数 ( a_1, a_2, \ldots, a_n )((0 \le a_i \le 10^9)),表示数组中的元素。

输出描述

输出一个整数,表示至少需要多少个队列,才能完成上述流程并保证最终输出严格递减。

样例输入

9

8 4 2 5 3 7 1 6 0

样例输出

4

说明:在这个样例中,其中一个分配阶段的展示是:第一个队列依次放入 (8, 4, 2);第二个队列依次放入 (5, 3, 1);第三个队列放入 (7);最后第四个队列依次放入 (6, 0)。可以证明四个队列是所需要的最少的队列的数量。

参考题解

C++:

#include <bits/stdc++.h>
using namespace std;

// 计算数组的 LIS 长度(非严格递增:使用 lower_bound)
int lis_length(const vector<long long>& arr) {
    if (arr.empty()) return 0;
    vector<long long> tails;  // tails[len-1] = 长度为 len 的递增子序列的最小尾值
    for (auto x : arr) {
        auto it = lower_bound(tails.begin(), tails.end(), x);
        if (it == tails.end()) tails.push_back(x);
        else *it = x;
    }
    return (int)tails.size();
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n)) return 0;
    vector<long long> evens, odds;
    evens.reserve(n);
    odds.reserve(n);

    for (int i = 0; i < n; ++i) {
        long long x; cin >> x;
        if ((x & 1LL) == 0) evens.push_back(x);
        else odds.push_back(x);
    }

    cout << lis_length(evens) + lis_length(odds) << "\n";
    return 0;
}

Java:

import java.io.*;
import java.util.*;

public class Main {
    // 简单快速输入
    static class FastScanner {
        private final InputStream in;
        private final byte[] buffer = new byte[1 << 16];
        private int ptr = 0, len = 0;
        FastScanner(InputStream is) { this.in = is; }
        private int read() throws IOException {
            if (ptr >= len) {
                len = in.read(buffer);
                ptr = 0;
                if (len <= 0) return -1;
            }
            return buffer[ptr++];
        }
        long nextLong() throws IOException {
            int c; long sgn = 1, x = 0;
            do { c = read(); } while (c <= ' ');
            if (c == '-') { sgn = -1; c = read(); }
            while (c > ' ') { x = x * 10 + (c - '0'); c = read(); }
            return x * sgn;
        }
        int nextInt() throws IOException { return (int) nextLong(); }
    }

    // 计算数组的 LIS 长度(非严格递增:lower_bound)
    static int lisLength(List<Long> arr) {
        if (arr.isEmpty()) return 0;
        ArrayList<Long> tails = new ArrayList<>();
        for (long x : arr) {
            int pos = lowerBound(tails, x);
            if (pos == tails.size()) tails.add(x);
            else tails.set(pos, x);
        }
        return tails.size();
    }

    // 在非降序列表中找第一个 >= target 的位置
    static int lowerBound(ArrayList<Long> a, long target) {
        int l = 0, r = a.size();
        while (l < r) {
            int mid = (l + r) >>> 1;
            if (a.get(mid) >= target) r = mid;
            else l = mid + 1;
        }
        return l;
    }

    public static void main(String[] args) throws Exception {
        FastScanner fs = new FastScanner(System.in);
        int n = fs.nextInt();

        ArrayList<Long> evens = new ArrayList<>(n);
        ArrayList<Long> odds  = new ArrayList<>(n);

        for (int i = 0; i < n; i++) {
            long x = fs.nextLong();
            if ((x & 1L) == 0) evens.add(x);
            else odds.add(x);
        }

        int ans = lisLength(evens) + lisLength(odds);
        System.out.println(ans);
    }
}

Python:

import sys
import bisect

input = sys.stdin.read
data = input().split()

n = int(data[0])
a = list(map(int, data[1:]))

evens = [x for x in a if x % 2 == 0]
odds = [x for x in a if x % 2 != 0]

def lis_length(arr):
    ifnot arr:
        return0
    tails = []
    for num in arr:
        pos = bisect.bisect_left(tails, num)
        if pos == len(tails):
            tails.append(num)
        else:
            tails[pos] = num
    return len(tails)

print(lis_length(evens) + lis_length(odds))

第二题:小C的矩阵

给定一个 ( n \times m ) 的矩阵。矩阵第 ( i ) 行第 ( j ) 列的初始值记为 ( v_{i,j} )。

给定一个长度为 ( n ) 的数组 ({a_1, a_2, \ldots, a_n}),以及一个长度为 ( m ) 的数组 ({b_1, b_2, \ldots, b_m})。

对于每个位置 ((i, j)) 的权值为:( w_{i,j} = v_{i,j} \times (a_i + b_j) )

你可以对矩阵进行任意次以下操作(数组 ( a, b ) 不会随操作改变):

  • 交换矩阵中任意两行所有同列的值(行变换);
  • 交换矩阵中任意两列所有同行的值(列变换)。

请通过这些操作,使得矩阵的权值和最大化。

【名词解释】

  • 行变换:行变换就是选取两个不同的行,将它们互换。
  • 列变换:列变换就是选取两个不同的列,将它们互换。

输入描述

第一行输入两个整数 ( n, m )((1 \le n, m \le 10^3)),分别表示矩阵的行数和列数。

第二行输入 ( n ) 个整数 ( a_1, a_2, \ldots, a_n )((1 \le a_i \le 10^4)),表示每行的权值。

第三行输入 ( m ) 个整数 ( b_1, b_2, \ldots, b_m )((1 \le b_j \le 10^4)),表示每列的权值。

接下来 ( n ) 行,每行输入 ( m ) 个整数 ( v_{i,1}, v_{i,2}, \ldots, v_{i,m} )((1 \le v_{i,j} \le 10^4)),表示矩阵的初始值。

输出描述

输出一个整数,表示通过任意次行变换或列变换后,矩阵权值和的最大值。

样例输入

1 3

1

1 2 3

3 1 2

样例输出

20

参考题解

C++:

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    if (!(cin >> n >> m)) return 0;

    vector<long long> a(n), b(m);
    for (int i = 0; i < n; ++i) cin >> a[i];
    for (int j = 0; j < m; ++j) cin >> b[j];

    vector<long long> row_sums(n, 0), col_sums(m, 0);

    // 逐行读入矩阵并累加行和、列和,避免存整矩阵
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            long long v; cin >> v;
            row_sums[i] += v;
            col_sums[j] += v;
        }
    }

    // 降序排序以最大化点积
    sort(a.begin(), a.end(), greater<long long>());
    sort(b.begin(), b.end(), greater<long long>());
    sort(row_sums.begin(), row_sums.end(), greater<long long>());
    sort(col_sums.begin(), col_sums.end(), greater<long long>());

    long long max_total_weight = 0;

    for (int i = 0; i < n;

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

2025 春招笔试合集 文章被收录于专栏

2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南

全部评论

相关推荐

8.6投递&nbsp;-&gt;8.12一面&nbsp;-&gt;&nbsp;8.16测评&nbsp;-&gt;&nbsp;8.18二面&nbsp;-&gt;&nbsp;8.19&nbsp;笔试(下次再笔试实习冲突)一面:1、MCP,Agent,langchain,RAG相关拷打;2、MCP用什么通信,你项目怎么用的;3、你对图像理解模型有什么理解,你们的生图模型多少B,用的什么卡;4、你对GPT5有什么看法,用过没;5、JVM八股;6、设计模式八股;7、Spring&nbsp;AI相关提问;8、sse,stdio,websocket区别;9、实习提问。算法:电话号码的字母组合二面:1、自我介绍;2、上来就做题:从第K个节点开始翻转链表;3、进程,线程,协程区别;4、为什么说用户态到内核态开销大,进程线程协程都切换了什么东西;5、虚拟线程的底层实现;6、linux里面是怎么拉起进程的,比如说怎么拉起jar包的;7、Http1.1,Http2,Http3各自区别,QUIC协议基于什么;8、Https和Http区别,TLS四次握手过程;9、进程的状态流转,进程阻塞等待时候在干什么;10、进程等待的时候,如果有web请求进来是怎么通知进程的,系统中断是什么;11、重放攻击,中间人攻击,为什么TLS四次握手交换的是随机数,数字证书是什么;12、为什么Https只有密钥是非对称加密的,什么是前向安全。反问:面试官觉得在他角度我表现可以了,有些东西我觉得我没讲清楚但是他能get到我意思(非科班操作系统计网这一块确实比较薄弱,面试官人很好一直引导,还是得好好复盘),要等候选人都面完再评估二面结果,希望可以过吧
查看21道真题和解析
点赞 评论 收藏
分享
07-22 14:39
门头沟学院 C++
皮格吉:笔试?我怎么ai完直接就是面试了?
投递小鹏汽车等公司10个岗位
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务