小红书 2024/03/24 暑期实习笔试真题

899 阅读5分钟

思路借鉴于2024.3.24小红书暑期实习笔试多语言AK指南 - 知乎 (zhihu.com),主要是针对真题的二次解释,所有程序仅通过样例,可能存在错误,最后一题暂时没用java重写。

难度:第一、二道是简单题,第三道是略难的简单题,第四道和第五道是中等偏上题。

第一道是“模拟 + 哈希表”,第二道是“三维数组动态规划”(第三维<=2),第三道是“模拟+二分查找”

T1

image-20240407124009722.png

样例

输入

8
a
b
a
c
a
a
a
a

输出

a
b
c

思路:模拟 哈希表

我们可以维护一个哈希表来记录当前单词有没有出现,如果没出现过,则说明是第一次出现,直接输出当前单词,并将当前单词添加到哈希表中即可 时间复杂度:O(n)

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Set<String> st = new HashSet<>();  // 判断当前单词是否出现过
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        for(int i = 0; i < n; i++) {
            String s = scanner.next();
            if(!st.contains(s)) { // 是否包含
                System.out.println(s);  // 如果不包含,则输出
            }
            st.add(s); // 加入Set中
        }
    }
}

T2

image-20240407124547240.png

样例

输入

5 8
1 2 3 4 10

输出

2

image-20240407124638619.png

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建一个 Scanner 对象,用于读取输入
        int n = scanner.nextInt(); // 读取旧帐号的数量
        int x = scanner.nextInt(); // 读取新账号需要的粉丝数
        int[] w = new int[n + 1]; // 创建数组用于存储每个旧帐号的粉丝数量
        for(int i = 1; i <= n; i++) w[i] = scanner.nextInt(); // 读取每个旧帐号的粉丝数量并存储到数组中
        // 定义为从前i个旧账号中选择,且粉丝量为j,使用了k次多次推广(k<=1)的最小选择的旧帐号数量
        int[][][] f = new int[n + 1][x + 1][2]; // 用于动态规划
        for(int[][] arr : f) { // 初始化数组,将所有元素设置为一个较大的值
            for(int[] subArr : arr) {
                Arrays.fill(subArr, Integer.MAX_VALUE / 2);
            }
        }
        f[0][0][0] = 0; // 初始状态
        for(int i = 1; i <= n; i++) { // 动态规划主循环,遍历旧帐号
            for(int j = 0; j <= x; j++) { // 遍历粉丝数
                for(int k = 0; k < 2; k++) { // 遍历状态
                     // 不变或不选择当前旧帐号,一开始 Integer.MAX_VALUE / 2 > f[i-1][j][k],之后就是正常比较
                    f[i][j][k] = Math.min(f[i][j][k], f[i - 1][j][k]);
                    if(j >= w[i] / 2) { // 如果当前还需要的粉丝数>=选取当前帐号一半的粉丝数,例如 6 > 4 > 3(6/2)
                        // 不变或者选取该账号的一半粉丝数,选取最小值
                        f[i][j][k] = Math.min(f[i][j][k], f[i - 1][j - w[i] / 2][k] + 1); 
                    }
                    if(j >= w[i] && k > 0) { // 如果当前还需要的粉丝数>=选取当前帐号,并且判断是否进行一次多次推荐(仅当目前粉丝数>=该账户拥有的粉丝数才进行)
                        // 不变或者选取该账号的所有的粉丝数,选取最小值
                        // 注意此处需要k-1,因为是多次推荐(要第i个账号的全部粉丝)
                        f[i][j][k] = Math.min(f[i][j][k], f[i - 1][j - w[i]][k - 1] + 1);
                    }
                }
            }
        }
        int res = Math.min(f[n][x][0], f[n][x][1]); // 判断是否需要多次推荐
        if(res == Integer.MAX_VALUE / 2) System.out.println("-1"); // 找不到合适的数组成推荐数
        else System.out.println(res);
	}
}

T3

image-20240407142225942.png

样例

输入

3
3 1 4

输出

9
15
8

image-20240407142249350.png

import java.util.*;

public class Main {
    static int n; // 题解数量
    static int[] a; // 每个笔记的点赞数
    static long sum = 0; // 原始的总点赞数
    // c1是当前笔记点赞数的增量,即最大点赞数x=c1+当前点赞数
    // c2是除当前笔记点赞数的增量,即c2 = x * (n - 1) - (sum - a_i)
    // 因为是当前笔记和其他笔记交替点赞,所以c1-c2<=1,这里先点击当前笔记,即先点击c1

    // 检查当前点赞数是否符合条件
    static boolean check(long a_i, long x) {
        // 如果当前点赞数 x 减去当前笔记的点赞数 a_i 小于等于剩余笔记的总点赞数加上 1,那么就认为当前点赞数 x 可以满足条件,即当前笔记所需的额外点赞数小于等于剩余笔记的总点赞数加上 1。
        // 也就是说只允许 x - a_i
        return x - a_i <= x * (n - 1) - (sum - a_i) + 1; // c1 <= c2+1
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt(); // 读取题解数量n
        a = new int[n]; // 初始化数组用于存储每个笔记的点赞数
        int maxv = 0; // 初始化最大点赞数
        // 读取每个笔记的点赞数,并计算总点赞数和最大点赞数
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
            sum += a[i];
            maxv = Math.max(maxv, a[i]); // 更新最大点赞数
        }
        // 处理特殊情况:如果题解数量为2
        if (n == 2) {
            for (int i = 0; i < n; i++) {
                if (a[i] == maxv) System.out.println(a[i]); // 如果当前笔记的点赞数是最大点赞数,输出该点赞数
                else System.out.println("-1"); // 否则输出-1
            }
        }
        // 对于每个笔记,计算满足条件的最小点赞数,在[maxv,1e12]中寻找
        for (int i = 0; i < n; i++) {
            long l = maxv, r = (long)1e12; // 设置二分搜索的左右边界
            while (l < r) {
                long mid = l + (r - l) / 2; // 计算中间点
                if (check(a[i], mid)) r = mid; // 如果当前点赞数符合条件,将右边界缩小到mid
                else l = mid + 1; // 否则将左边界扩大到mid+1
            }
            // 计算并输出最小点赞数,总点赞数加上其他笔记的最大点赞数减去当前笔记的点赞数(除当前笔记外其他笔记的总点赞数),并加上0或当前笔记的最大点赞数减去当前笔记的点赞数再减去1中的最大值(除当前笔记外其他笔记的最大点赞数。)。
            // res = sum + c1 + c2(c2>=0),原始总点赞数+当前笔记点赞增量+其他笔记点赞增量
            long res = sum + l - a[i] + Math.max(0, l - a[i] - 1);
            System.out.println(res);
        }
    }
}