【2023秋招】9.26字节跳动笔试

⭐️前言⭐️

hello 大家好,我是万里,9.26 我参与了字节跳动的笔试,并成功将其 AK(all-killed)。

众所周知,国庆虽然拥有 7 天的长假(部分好兄弟可能只有 3 天),但真正享受假期的人却寥寥无几,毕竟在今年互联网就业环境并不乐观的情况下,大家只能靠卷来平复自己那颗躁动的心。俗话说得好:国庆一时爽,面试火葬场。为了能斩获大厂的 o f f e r offer offer,请尽快和我一起卷起来吧!

题解

A.族谱

  • 难度:☆☆
  • 考点:模拟

【题目简述】

某家族子孙众多,但保留了部分的家族族谱,现在公司想知道该家族的第一代人是谁以及第 M M M 代人的数量。

【输入描述】

输入的第一行包含一个整数 N < 100 N<100 N<100,表示保留了的族谱数量。

2 ∼ N + 1 2\sim N+1 2N+1 行每行包含一个字符串数组(数组长度不确定),形如:如: [ A , B , C ] [A,B,C] [A,B,C],其含为 A A A B B B 的父亲, B B B C C C 的父亲。

输入的第一行包含一个整数 M M M,其含义如题意所述。

【输出描述】

输出包含两行,第一行为家族第一代人的姓名,第二行为家族第 M M M 代人的数量。

解题思路

题目有两个问题:

  1. 求出第一代人是谁
  2. 求出第 M M M 代人的数量

为了方便后续的处理,我们可以先读入 N N N 组数据,并将 N N N 组数据中涉及到的所有人离散化(字符串转数字,如 A → 1 , B → 2 , C → 3 A\rightarrow 1,B\rightarrow2,C\rightarrow3 A1,B2,C3)。

对于问题1,我们可以维护一个数组: d u [ ] du[] du[],其中 d u [ i ] du[i] du[i] 表示第 i i i 个人的父亲的数量。

若族谱信息为: [ A , B , C ] [A,B,C] [A,B,C],则我们令: d u [ 2 ] + + , d u [ 3 ] + + du[2]++,du[3]++ du[2]++,du[3]++ 2 , 3 2,3 2,3 分别表示 B , C B,C B,C)。那么在处理完所有族谱信息后,我们遍历 d u [ ] du[] du[] 数组,其中 d u [ i ] = 0 du[i]=0 du[i]=0 i i i 即为所求。

问题1解决。

对于问题2,我们可以建立“父-子边”(即父亲指向孩子的单向边)。只要题目的输入数据合法(不存在 A A A B B B 的父亲, B B B 又是 A A A 的父亲的情况),那么建完边后所得到的图就必然是棵树。

建立完所有边后,我们从第一代人(祖先)开始 DFS 遍历树,并用 d e p [ ] dep[] dep[] 数组维护树的高度,那么在遍历树的过程中,我们只要统计高度等于 M M M 的节点数量即可得到答案。

B.子串

  • 难度:☆
  • 考点:思维

【题目简述】

给定一个长度为 n n n 的数组 a 0 , a 1 , a 2 , ⋯   , a n − 1 a_0,a_1,a_2,\cdots,a_{n-1} a0,a1,a2,,an1,以及一个常数 k k k,请你求出数组 a a a 中有多少个满足以下条件的、长度为 k + 1 k+1 k+1 的子串:

  • 2 0 ⋅ a i < 2 1 ⋅ a i + 1 < 2 2 ⋅ a i + 2 < ⋯ < 2 k ⋅ a i + k 2^0\cdot a_i < 2^1 \cdot a_{i+1}<2^2\cdot a_{i+2} < \cdots < 2^k\cdot a_{i+k} 20ai<21ai+1<22ai+2<<2kai+k

【输入描述】

包含多组测试数据。

第一行给定一个 T T T,表示测试数据的个数。

接下来的 T T T 组测试数据,每组数据首先给定两个整数 n , k n,k n,k,,紧接着输入 n n n 个整数,表示 a 0 , a 2 , ⋯   , a n − 1 a_0,a_2,\cdots,a_{n-1} a0,a2,,an1

  • 1 ≤ T ≤ 5 1\leq T \leq 5 1T5
  • 3 ≤ n ≤ 1 0 5 3\leq n \leq 10^5 3n105
  • 0 < k < n 0< k < n 0<k<n
  • 0 < a i ≤ 1 0 8 0< a_i \leq 10^8 0<ai108

解题思路

先来思考一个问题,假设现在有一个长度为 x x x 的数组 b [ ] b[] b[],满足:
2 0 ⋅ b 0 < 2 1 ⋅ b 1 < 2 2 ⋅ b 2 < ⋯ < 2 x − 1 b x − 1 2^0\cdot b_0 < 2^1\cdot b_1 < 2^2\cdot b_2 < \cdots < 2^{x-1}b_{x-1} 20b0<21b1<22b2<<2x1bx1
那么,其中满足题目限制条件的、长度为 k + 1 k+1 k+1 的子串有多少呢?

我想绝大多数人都能分析的出来:答案是 x − ( k + 1 ) + 1 x - (k+1) + 1 x(k+1)+1,即 x − k x-k xk

简单解释一下:由于整个数组都满足条件,所以其任意长度为 k + 1 k+1 k+1 的子串也必然满足条件。一个长度为 x x x 的数组拥有 x − ( k + 1 ) + 1 x-(k+1)+1 x(k+1)+1 个长度为 k + 1 k+1 k+1 的子串,固答案为 x − k x-k xk

同理,如果数组 a a a 的某个子串长度为 y y y,并且满足题目给出的条件,那么该子串所能为答案带来的贡献就为 y − ( k + 1 ) − 1 y-(k+1)-1 y(k+1)1(注意,若 y < k yy<k,则该子串对答案的贡献为 0 0 0)。

于是,我们就可以从头开始遍历数组 a a a,找出其中所有满足题目条件的子串,并根据这些子串的长度,计算它们对答案的贡献。

为了避免贡献被重复计算,我们规定数组的一个元素,只能属于一个子串。

举个例子: a = [ 22 , 12 , 16 , 4 , 3 , 22 , 12 ] a = [22,12,16,4,3,22,12] a=[22,12,16,4,3,22,12],那么满足条件的子串有:

  • [ 22 , 12 , 16 ] [22,12,16] [22,12,16],长度为 3 3 3
  • [ 4 , 3 , 22 , 12 ] [4,3,22,12] [4,3,22,12],长度为 4 4 4

k = 2 k=2 k=2,则答案为 ( 3 − 2 ) + ( 4 − 2 ) = 3 (3-2)+(4-2) = 3 (32)+(42)=3

k = 3 k=3 k=3,则答案为 ( 3 − 3 ) + ( 4 − 3 ) = 1 (3-3) + (4-3) = 1 (33)+(43)=1

k = 4 k=4 k=4,则答案为 m a x ( 0 , 3 − 4 ) + ( 4 − 4 ) = 0 max(0,3-4) + (4-4) = 0 max(0,34)+(44)=0

至此,完成解题。

C. AB实验

【题目简述】

你当前位于位置 x x x,你需要走到位置 y y y

假设每一步对应一个位置。从 x x x 走到 y y y,每一步的长度都是正整数,每一步的值等于上一步的值 -1 或 +0 或 +1,问从 x x x 走到 y y y 最少要走几步。

注意:你走的第一步必须是 1 1 1,最后一步也必须是 1 1 1

【输入格式】

第一行给定一个整数 T T T,表示有 T T T 组测试数据。

对于每组测试数据,给定两个整数 x , y x,y x,y,其含义如上所述。

【输出格式】

对于每个测试数据,输出一个整数,表示从 x x x 走到 y y y 的最少步数,即答案。

1 ≤ T ≤ 1 0 3 1\leq T\leq 10^3 1T103

0 ≤ x ≤ y ≤ 2 31 0\leq x \leq y \leq 2^{31} 0xy231

题目分析

吐槽:题目明确规定 x ≤ y x\leq y xy,但样例中却出现 x > y x > y x>y 的情况,真是让人无 fuck 说。

为了让我们所走的步数尽可能地少,我们得保证所走的每一步的值都要尽可能地大

不妨假设我们在从 x x x y y y 的过程中,所走的最大值为 n n n

由于我们所走的第一步、最后一步的值都是 1 1 1,且每一步与上一步的差值不会超过 1 1 1,因此我们所走的路线一定会包含一个(非严格)递增序列以及一个(非严格)递减序列: 1 , 2 , 3 , ⋯   , n , ⋯   , 3 , 2 , 1 1,2,3,\cdots, n,\cdots,3,2,1 1,2,3,,n,,3,2,1

对于 1 , 2 , 3 , ⋯   , n , ⋯   , 3 , 2 , 1 1,2,3,\cdots, n,\cdots,3,2,1 1,2,3,,n,,3,2,1,我们称其为固定步。

x x x y y y 需要走的距离为 y − x y-x yx,减去固定步: 1 , 2 , 3 , n , max ⁡ , … , 3 , 2 , 1 1,2,3,n,\max,\dots,3,2,1 1,2,3,n,max,,3,2,1 后,剩余需要走的距离为:
y − x − 1 , 2 , 3 , ⋯   , n , … , 3 , 2 , 1 = y − x − ( 2 × n ( n + 1 ) 2 − n ) = y − x − n × ( n + 1 ) + n \begin{aligned} y-x-1,2,3,\cdots,n,\dots,3,2,1&=y-x-(2\times \dfrac{n(n+1)}{2}-n)\\ &=y-x-n\times(n+1)+n \end{aligned} yx1,2,3,,n,,3,2,1=yx(2×2n(n+1)n)=yxn×(n+1)+n
为了方便阐述,我们可以定义 c h a cha cha 表示剩余需要走的距离,起初 c h a = y − x − n × ( n + 1 ) + n cha = y-x-n\times(n+1)+n cha=yxn×(n+1)+n

我们来对 c h a cha cha 进行一波分类讨论:

  1. c h a = 0 cha = 0 cha=0 时:已到达位置 y y y,总共走的步数为 2 × n − 1 2\times n - 1 2×n1(固定步数)。

  2. 0 < c h a ≤ n 0< cha \leq n 0<chan 时:距离位置 y y y 仅有一步之遥,我们可以在固定步的基础上多走一步到达 y y y,即:

    • 固定步:
      1 , 2 , 3 , ⋯   , c h a , c h a + 1 , ⋯   , n , ⋯   , c h a + 1 , c h a , ⋯   , 3 , 2 , 1 1,2,3,\cdots,cha,cha+1,\cdots,n,\cdots,cha+1,cha,\cdots,3,2,1 1,2,3,,cha,cha+1,,n,,cha+1,cha,,3,2,1

    • 多走一步:
      1 , 2 , 3 , ⋯   , c h a , c h a , c h a + 1 , ⋯   , n , ⋯   , c h a + 1 , c h a , ⋯   , 3 , 2 , 1 1,2,3,\cdots,cha,cha,cha+1,\cdots,n,\cdots,cha+1,cha,\cdots,3,2,1 1,2,3,,cha,cha,cha+1,,n,,cha+1,cha,,3,2,1

    • 或:
      1 , 2 , 3 , ⋯   , c h a , c h a + 1 , ⋯   , n , ⋯   , c h a + 1 , c h a , c h a , ⋯   , 3 , 2 , 1 1,2,3,\cdots,cha,cha+1,\cdots,n,\cdots,cha+1,cha,cha,\cdots,3,2,1 1,2,3,,cha,cha+1,,n,,cha+1,cha,cha,,3,2,1
      总共走的步数为 ( 2 × n − 1 ) + 1 = 2 × n (2\times n - 1) + 1 = 2\times n (2×n1)+1=2×n

  3. c h a > n cha > n cha>n 时:此时我们并没法通过一步来到达 y y y
    为了使我们走的步数尽可能少,我们要保证每步走的值尽可能大。于是,我们可以轻易地制定贪心策略:

    c h a > n cha > n cha>n ,则我们每一步都走 n n n,直到 c h a ≤ n cha \leq n chan(变为情况 1 1 1 或情况 2 2 2)。

    该策略总共要走的步数为 2 × n − 1 + ⌈ c h a n ⌉ 2\times n - 1 + \lceil \dfrac{cha}{n} \rceil 2×n1+ncha ⌈ ⌉ \lceil \rceil 表示向上取整。

在经过上述讨论后,不难发现,我们只要能取到一个最大值 n n n,就能快速计算出需要走的步数。

对于最大值 n n n,我们可以采用枚举法来确定,即逐一判断最大值取不同数时对应的不同步数,再从中取最优解作为答案。

不过既然采用枚举法,就要确定枚举的上限:根据 x , y ≤ 2 31 − 1 x,y\leq 2^{31}-1 x,y2311 可得 x , y x,y x,y 之间的距离最大为 2 31 2^{31} 231 左右。

最大值 n n n 的固定步数对应的距离为 1 + 2 + 3 + ⋯ + n + ⋯ + 3 + 2 + 1 = n ( n + 1 ) − n 1+2+3+\cdots + n +\cdots + 3 + 2 + 1 = n(n+1) - n 1+2+3++n++3+2+1=n(n+1)n。由于我们走的每一步都必须为正数(不能往回走),所以需要保证:
n ( n + 1 ) − n < 2 31 n(n+1) - n < 2^{31} n(n+1)n<231
可得 n n n 的最大取值为 5 × 1 0 4 5\times 10^4 5×104 左右。

总时间复杂度为 O ( T × n ) = O ( 1000 × 5 × 1 0 4 ) = O ( 5 × 1 0 7 ) O(T\times n) = O(1000\times 5\times 10^4) = O(5\times 10^7) O(T×n)=O(1000×5×104)=O(5×107)

喂狗粮

  • 难度:☆☆
  • 考点:动态规划

【题目简述】

小明买了只狗以及一包 M M M 克的狗粮。

小狗每天可能会吃 a 1 a_1 a1 a 2 a_2 a2 ⋯ \cdots 狗粮。

只要狗粮的数量不为 0 0 0,那么即使当天狗粮不够小狗吃,小狗那天也算吃了一天的狗粮。

现已知小狗后一天吃的狗粮不会比前一天多,问它吃完这包狗粮一共会有多少种情况?

【输入格式】

输入共两行。

第一行:空格分割小狗每天的可能的食量 a 1 , a 2 , ⋯ a_1,a_2,\cdots a1,a2,,最多 10 10 10 个。

第二行:输入 M M M,表示狗粮一共有多少克。

【输出格式】

输出一个整数,表示这袋狗粮小狗吃完的情况数。

1 ≤ a i , M ≤ 1 0 4 1\leq a_i,M \leq 10^4 1ai,M104

题目分析

既然要求的是情况数,那么不妨考虑动态规划。

根据题目已有信息,我们可以定义 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示剩余狗粮为 i i i,上一天吃的狗粮为 j j j 的方案(情况)数。

整个 d p dp dp 的转移我们可以使用三个 f o r for for 循环来实现:

  1. 第一个 f o r for for 枚举 i i i i i i 用以表示当天吃的狗粮量
  2. 第二个 f o r for for 枚举 j j j j j j 用以表示当前剩余狗粮量
  3. 第三个 f o r for for 枚举 k k k k k k 用以表示上一天吃的狗粮量

根据由题意可得,当 a [ k ] ≥ a [ i ] a[k] \geq a[i] a[k]a[i] 时:
d p [ i ] [ j ] + = d p [ k ] [ j + a [ k ] ] dp[i][j] += dp[k][j + a[k]] dp[i][j]+=dp[k][j+a[k]]
总时间复杂度为 O ( 10 × 1 0 4 × 1 0 4 ) = O ( 1 0 9 ) O(10\times 10^4 \times 10^4) = O(10^9) O(10×104×104)=O(109)

由于本题存在约束条件,即小狗当天吃的狗粮量不会大于上一天狗粮量,所以我们可以进行相应剪枝,降低常数来通过本题。

结语

当下互联网各大厂越来越注重算法,算法也往往会被用来衡量你的代码能力。作为想要顺利拿到大厂 o f f e r offer offer 的你,算法是必不可缺的一项技能。如果你认为自己的算法水平薄弱,或是需要有人督促学习,那么请添加我的 QQ:670369632,我会每日挑选一道题经典算法题,与你分享交流,并督促你刷题。

你可能感兴趣的:(算法,求职招聘,面试)