京东笔试 京东笔试题 0809

笔试时间:2025年8月9日

往年笔试合集:

2023春招秋招笔试合集

2024春招秋招笔试合集

第一题:子序列的字典序

现在有一个长度为 n 的数字序列,每个数都在 1~k 的范围内,且 1~k 内每个数字都至少出现过一次。现在我们想在这其中找一个子序列,使得 1~k 恰好出现一次,且字典序最小。请你通过程序得出结果。我们认为:B 是 A 的子序列,当且仅当可以从 A 中删除 0 个或任意个元素之后按照原来的顺序拼接起来得到 B。序列 A 的字典序小于 B,当且仅当存在一个位置 k,使得 A[k] < B[k] 且 A[i] = B[i](i = 1..k-1)。

输入描述

第一行两个空格隔开的正整数 n 和 k;

第二行 n 个空格隔开的正整数,表示该数字序列 a。

约束:1 ≤ k ≤ n ≤ 5×10⁴,1 ≤ aᵢ ≤ k

输出描述

输出一行 k 个数字,表示字典序最小的子序列。不要输出行末空格。

样例输入

5 3  

2 1 3 3 2

样例输出

1 3 2  

提示:其中一种可行的方案为:2(1)3(3)2,选定括号中的数字,构成子序列,可知此时字典序最小。

参考题解

本题使用贪心+单调栈的的思路, 问题本质分析:需要从原数组中选出长度为 k 的子序列(保持原顺序),且该子序列的字典序最小。字典序最小的核心是「前面的元素尽可能小」,这天然指向「贪心策略」—— 每一步都选择当前能选的最小元素。贪心的约束:选择小元素时不能 “只顾眼前”,必须保证后面还有足够的元素来凑齐 k 个。例如,若当前栈顶元素较大,但后面再也没有该元素了,就不能弹出它(否则凑不够 k 个)。因此需要统计每个元素剩余的出现次数,作为能否弹出栈顶的依据。单调栈的适配性:要维护 “前面元素尽可能小” 的序列,单调栈是天然的工具。栈可以动态维护已选元素,通过弹出 “较大且后续仍有出现” 的栈顶元素,确保新加入的元素能让序列更优(字典序更小)。同时栈的长度可以直观地控制在 k 以内,满足子序列长度要求。去重需求:若问题隐含 “子序列元素不重复”(从代码中 inStack 的判断可推测),则需要额外记录元素是否已在栈中,避免重复加入破坏唯一性。因此,贪心策略保证了 “选最小” 的核心目标,单调栈提供了动态维护序列的高效方式,剩余次数统计解决了 “凑够 k 个” 的约束

C++:

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

vector<int> smallestSubsequence(vector<int>& a, int k) {
    int n = a.size();
    // 统计每个数字剩余出现的次数
    unordered_map<int, int> count;
    for (int num : a) {
        count[num]++;
    }

    vector<int> stack;
    // 记录栈中是否已经包含某个数字
    unordered_map<int, bool> inStack;

    for (int num : a) {
        // 每遍历一个数字,该数字剩余出现次数减 1
        count[num]--;

        // 如果数字已经在栈中,跳过
        if (inStack[num]) continue;

        // 维护单调栈的字典序最小性质
        while (!stack.empty() && stack.back() > num && count[stack.back()] > 0) {
            inStack[stack.back()] = false;
            stack.pop_back();
        }

        stack.push_back(num);
        inStack[num] = true;

        // 当栈的大小达到 k 时,提前终止(已经找到结果)
        if (stack.size() == k) break;
    }

    return stack;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    vector<int> result = smallestSubsequence(a, k);

    for (int i = 0; i < k; i++) {
        cout << result[i];
        if (i != k - 1) {
            cout << " ";
        }
    }
    cout << endl;

    return 0;
}

Java:

import java.util.*;

public class SmallestSubsequence {
    public static List<Integer> smallestSubsequence(int[] a, int k) {
        int n = a.length;
        // 统计每个数字剩余出现的次数
        Map<Integer, Integer> count = new HashMap<>();
        for (int num : a) {
            count.put(num, count.getOrDefault(num, 0) + 1);
        }

        Deque<Integer> stack = new ArrayDeque<>();
        // 记录栈中是否已经包含某个数字
        Map<Integer, Boolean> inStack = new HashMap<>();

        for (int num : a) {
            // 每遍历一个数字,该数字剩余出现次数减 1
            count.put(num, count.get(num) - 1);

            // 如果数字已经在栈中,跳过
            if (inStack.getOrDefault(num, false)) {
                continue;
            }

            // 维护单调栈的字典序最小性质
            while (!stack.isEmpty() && stack.peekLast() > num && count.get(stack.peekLast()) > 0) {
                inStack.put(stack.peekLast(), false);
                stack.pollLast();
            }

            stack.offerLast(num);
            inStack.put(num, true);

            // 当栈的大小达到 k 时,提前终止(已经找到结果)
            if (stack.size() == k) {
                break;
            }
        }

        return new ArrayList<>(stack);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
        }

        List<Integer> result = smallestSubsequence(a, k);

        for (int i = 0; i < k; i++) {
            System.out.print(result.get(i));
            if (i != k - 1) {
                System.out.print(" ");
            }
        }
        System.out.println();
    }
}

Python:

from collections import defaultdict

def smallest_subsequence(a, k):
    n = len(a)
    # 统计每个数字剩余出现的次数
    count = defaultdict(int)
    for num in a:
        count[num] += 1

    stack = []
    # 记录栈中是否已经包含某个数字
    in_stack = defaultdict(bool)

    for num in a:
        # 每遍历一个数字,该数字剩余出现次数减 1
        count[num] -= 1

        # 如果数字已经在栈中,跳过
        if in_stack[num]:
            continue

        # 维护单调栈的字典序最小性质
        while stack and stack[-1] > num and count[stack[-1]] > 0:
            in_stack[stack[-1]] = False
            stack.pop()

        stack.append(num)
        in_stack[num] = True

        # 当栈的大小达到 k 时,提前终止(已经找到结果)
        if len(stack) == k:
            break

    return stack

if __name__ == "__main__":
    import sys
    input = sys.stdin.read().split()
    idx = 0
    n = int(input[idx])
    idx += 1
    k = int(input[idx])
    idx += 1
    a = []
    for i in range(n):
        a.append(int(input[idx]))
        idx += 1

    result = smallest_subsequence(a, k)

    for i in range(k):
        print(result[i], end="")
        if i != k - 1:
            print(" ", end="")
    print()

第二题:01串划分

小钟有一个长度为 n 的 01 串 s(仅由字符 0 和 1 组成 ),另外还有 m 个数字,分别用 a₁, a₂, ..., aₘ 表示。小钟想知道,能否选择 m 个不相交的区间 [l₁, r₁], [l₂, r₂], ..., [lₘ, rₘ],使得对于任意的 aᵢ,其二进制表示(没有前导 0,0 的二进制表示就是 0 ),都能用 s 的某个连续子串 s[lⱼ, lⱼ + 1, ..., rⱼ] 来表示。

输入描述

输入包括多组测试数据:第一行输入一个正整数 T(1 ≤ T ≤ 20),表示测试数据的组数。每组测试数据的第一行有两个整数 n(1 ≤ n ≤ 100)

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

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

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

全部评论

相关推荐

A了1.2&nbsp;还能走到后面吗?
投递阿里云等公司10个岗位
点赞 评论 收藏
分享
点赞 评论 收藏
分享
0816&nbsp;京东笔试答案第一题,&nbsp;减少逆序对数量对于每个&nbsp;ai,&nbsp;找到&nbsp;所有&nbsp;aj&nbsp;=&nbsp;a[i]&nbsp;+&nbsp;1&nbsp;且&nbsp;j&nbsp;&lt;&nbsp;i&nbsp;的&nbsp;j,&nbsp;则对于选择&nbsp;j&nbsp;&lt;&nbsp;L&nbsp;&lt;=&nbsp;i&nbsp;的&nbsp;L&nbsp;贡献&nbsp;+1,&nbsp;然后做一个前缀和取最大值即可代码```#include&nbsp;&lt;iostream&gt;#include&nbsp;&lt;cstring&gt;#include&nbsp;&lt;algorithm&gt;#include&nbsp;&lt;vector&gt;#include&nbsp;&lt;unordered_map&gt;using&nbsp;namespace&nbsp;std;void&nbsp;solve(){int&nbsp;n;&nbsp;cin&nbsp;&gt;&gt;&nbsp;n;vector&lt;int&gt;&nbsp;a(n&nbsp;+&nbsp;10,&nbsp;0),&nbsp;b(n&nbsp;+&nbsp;10,&nbsp;0),&nbsp;c(n&nbsp;+&nbsp;10,&nbsp;0);unordered_map&lt;int,&nbsp;vector&lt;int&gt;&gt;&nbsp;pos;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;=&nbsp;n;&nbsp;i&nbsp;++){cin&nbsp;&gt;&gt;&nbsp;a[i];}for&nbsp;(int&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;=&nbsp;n;&nbsp;i&nbsp;++){int&nbsp;v&nbsp;=a[i];int&nbsp;t&nbsp;=&nbsp;v&nbsp;+&nbsp;1;if&nbsp;(pos.find(t)&nbsp;!=&nbsp;pos.end()){for&nbsp;(int&nbsp;j&nbsp;:&nbsp;pos[t]){if&nbsp;(j&nbsp;&lt;&nbsp;i){b[j&nbsp;+&nbsp;1]&nbsp;++;b[i&nbsp;+&nbsp;1]&nbsp;--;}}}pos[v].push_back(i);}int&nbsp;ans&nbsp;=&nbsp;0;int&nbsp;tmp&nbsp;=&nbsp;0;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;=&nbsp;n;&nbsp;i&nbsp;++){tmp&nbsp;+=&nbsp;b[i];ans&nbsp;=&nbsp;max(ans,&nbsp;tmp);}cout&nbsp;&lt;&lt;&nbsp;ans&nbsp;&lt;&lt;&nbsp;endl;}int&nbsp;main(){int&nbsp;_&nbsp;=&nbsp;1;cin&nbsp;&gt;&gt;&nbsp;_;while&nbsp;(_&nbsp;--){solve();}}```第二题,&nbsp;跳水打分解法类似求区间最值,&nbsp;维护每个长度为&nbsp;m&nbsp;的区间的最大值和最小值,&nbsp;然后遍历过去即可算出答案。代码```#include&nbsp;&lt;bits/stdc++.h&gt;#define&nbsp;PII&nbsp;pair&lt;long,&nbsp;long&gt;#define&nbsp;x&nbsp;first#define&nbsp;y&nbsp;secondusing&nbsp;namespace&nbsp;std;int&nbsp;main(){int&nbsp;n,&nbsp;m;cin&nbsp;&gt;&gt;&nbsp;n&nbsp;&gt;&gt;&nbsp;m;priority_queue&lt;PII&gt;&nbsp;maxPq;priority_queue&lt;PII,&nbsp;vector&lt;PII&gt;,&nbsp;greater&lt;PII&gt;&gt;&nbsp;minPq;vector&lt;long&nbsp;long&gt;&nbsp;a(n&nbsp;+&nbsp;10);double&nbsp;ans&nbsp;=&nbsp;0;long&nbsp;long&nbsp;tmp&nbsp;=&nbsp;0;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;=&nbsp;n;&nbsp;i&nbsp;++)&nbsp;cin&nbsp;&gt;&gt;&nbsp;a[i];for&nbsp;(int&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;=&nbsp;m;&nbsp;i&nbsp;++){maxPq.push({a[i],&nbsp;i});minPq.push({a[i],&nbsp;i});tmp&nbsp;+=&nbsp;a[i];}long&nbsp;long&nbsp;minV&nbsp;=&nbsp;minPq.top().x;long&nbsp;long&nbsp;maxV&nbsp;=&nbsp;maxPq.top().x;ans&nbsp;=&nbsp;double(tmp&nbsp;-&nbsp;minV&nbsp;-&nbsp;maxV)&nbsp;/&nbsp;(m&nbsp;-&nbsp;2);int&nbsp;ans2&nbsp;=&nbsp;1;int&nbsp;l&nbsp;=&nbsp;1,&nbsp;r&nbsp;=&nbsp;m;while&nbsp;(r&nbsp;&lt;&nbsp;n){//&nbsp;cout&nbsp;&lt;&lt;&nbsp;ans&nbsp;&lt;&lt;&nbsp;endl;tmp&nbsp;-=&nbsp;a[l];&nbsp;l&nbsp;++;r&nbsp;++;&nbsp;tmp&nbsp;+=&nbsp;a[r];minPq.push({a[l],&nbsp;l});&nbsp;minPq.push({a[r],&nbsp;r});maxPq.push({a[l],&nbsp;l});&nbsp;maxPq.push({a[r],&nbsp;r});while&nbsp;(minPq.top().y&nbsp;&lt;&nbsp;l)&nbsp;minPq.pop();while&nbsp;(maxPq.top().y&nbsp;&lt;&nbsp;l)&nbsp;maxPq.pop();if&nbsp;((double(tmp&nbsp;-&nbsp;minPq.top().x&nbsp;-&nbsp;maxPq.top().x)&nbsp;/&nbsp;(m&nbsp;-&nbsp;2))&nbsp;&gt;&nbsp;ans){ans&nbsp;=&nbsp;double(tmp&nbsp;-&nbsp;minPq.top().x&nbsp;-&nbsp;maxPq.top().x)&nbsp;/&nbsp;(m&nbsp;-&nbsp;2);ans2&nbsp;=&nbsp;l;}}cout&nbsp;&lt;&lt;&nbsp;ans2&nbsp;&lt;&lt;&nbsp;endl;}```
投递京东等公司10个岗位
点赞 评论 收藏
分享
阿里系笔试成绩互通吗?
投递阿里巴巴控股集团等公司10个岗位
点赞 评论 收藏
分享
评论
2
2
分享

创作者周榜

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