【备战春招必看】字节跳动2025届春招第1套笔试解析 | 大厂真题通关指南

✅ 字节跳动春招备战指南 ✅

💡 学习建议:

  • 先尝试独立解题(建议用时:90分钟/套)
  • 对照解析查漏补缺
  • 配套练习题库

互联网必备刷题宝典🔗

📢 字节跳动技术岗笔试重要信息速览

⏰ 笔试时间安排

  • 常规场次:每周六交替进行
    • 上午场 10:00~12:00
    • 晚间场 19:00~21:00
  • 通知时间:提前2天通过邮箱发送考试链接

🧩 笔试题型分布

岗位类型题目构成
算法岗选择题 + 4道编程
后端开发岗选择题 + 3道编程
前端/测试岗选择题 + 4道编程

⚙️ 考试设置要点

  • 考试平台:牛客网(ACM模式)
  • 监考要求
    • 必须开启笔记本前置摄像头
    • 禁止使用手机(需小程序锁定)
    • 允许使用本地IDE
  • 编程规范
    • 严格遵循输入输出格式
    • 注意时间复杂度控制(通常1s对应1e8次运算)

📚 笔试经验贴

(所有展示题面均已进行改编处理,保留核心考点)

本题库收录整理自:

  1. 互联网公开的笔试真题回忆版(经网友投稿)
  2. 各大技术社区公开讨论的经典题型
  3. 历年校招考生提供的解题思路

🔍 题库特点:

  • 100%真实笔试场景还原
  • 包含高频考点题型
  • 提供多语言实现参考
  • 持续更新2024届最新真题

⚠️ 注意事项:

  1. 所有题目均来自公开渠道,已进行改编脱敏处理
  2. 实际笔试可能出现题型变化,请以官方通知为准

🚀 春招备战指南

金三银四求职季即将到来!这里整理了最新字节跳动真题及解析,助你快速掌握笔试套路。建议重点突破以下题型:

  1. 动态规划/状态压缩
  2. 树形结构应用
  3. 字符串模式匹配
  4. 滑动窗口/双指针

(👇 下附最新笔试真题及详细解析 👇)


题目一:最小矩形面积

题目内容

小基拿到了一个长度为 2 n 2n 2n 的数组,他希望把数组中的元素分成 n n n 个二元组: ( x i , y i ) (x_i,y_i) (xi,yi)

每个二元组对应平面直角坐标系的一个点,然后小基希望用一个边和坐标轴平行的矩形将所有点囊括在内。小基希望最终矩形的面积尽可能小,你能帮帮他吗?

输入描述

第一行输入一个正整数 n n n

第二行输入 2 n 2n 2n 个正整数 a i a_i ai,代表数组的元素。

1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1n105

1 ≤ a i ≤ 1 0 9 1 ≤ a_i \le 10^9 1ai109

输出描述

一个整数,代表矩形的最小面积。

样例1

输入:

2
1 2 3 4

输出:

1

说明: ( 1 , 4 ) (1,4) (1,4) ( 2 , 3 ) (2,3) (2,3)

题解

2 n 2n 2n 个数从小到大排序,横坐标选前 n n n 个,纵坐标选后 n n n 个。对于 n n n x i x_i xi 来说,需要将其全部覆盖最小的长度为 w = m a x ( x i ) − m i n ( x i ) , i ∈ [ 1 , n ] w = max(x_i) - min(x_i),i \in [1, n] w=max(xi)min(xi)i[1,n],对于 y y y 来说也是同理,最终的面积为两者相乘。

参考代码

C++:

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int len;
    cin >> len;
    vector<int> nums(2 * len);
    for(int & val : nums) {
        cin >> val;
    }
    sort(nums.begin(), nums.end());
    ll w = nums[len - 1] - nums[0];
    ll h = nums.back() - nums[len];
    cout << w * h << "\n";
    return 0;
}

Python:

n = int(input())
arr = sorted(list(map(int, input().split())))
w = arr[n-1] - arr[0]
h = arr[-1] - arr[n]
print(w * h)

Java:

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int size = scan.nextInt();
        int[] data = new int[2*size];
        for(int i = 0; i < 2*size; i++) {
            data[i] = scan.nextInt();
        }
        Arrays.sort(data);
        long width = data[size-1] - data[0];
        long height = data[2*size-1] - data[size];
        System.out.println(width * height);
    }
}

题目二:特殊倍数子数组

题目内容

小基有一个数组,他想知道有多少连续子数组的和同时是 3 和 5 的倍数,但不是 4 的倍数。

输入描述

第一行输入一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) n(1n105) 表示数组长度。

第二行输入 n n n 个整数表示数组 a i ( 1 ≤ a i ≤ 1 0 9 ) a_i(1\le a_i\le 10^9) ai(1ai109)

输出描述

一个整数。

样例1

输入:

3
13 17 30

输出:

2

题解

使用前缀和 + 哈希表来解决。如果两个前缀和对 15 取模相等,说明这段区间和是 15 的倍数。同理,如果对 60 取模相等,说明是 60 的倍数。用容斥原理,答案 = 15 的倍数个数 - 60 的倍数个数。

参考代码

C++:

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

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for(int& x : arr) cin >> x;
    
    ll sum = 0, ans = 0;
    unordered_map<int,int> mod15, mod60;
    mod15[0] = mod60[0] = 1;
    
    for(int x : arr) {
        sum += x;
        int r15 = sum % 15;
        int r60 = sum % 60;
        ans += mod15[r15];
        ans -= mod60[r60];
        mod15[r15]++;
        mod60[r60]++;
    }
    cout << ans;
    return 0;
}

Python:

n = int(input())
arr = sorted(list(map(int, input().split())))
w = arr[n-1] - arr[0]
h = arr[-1] - arr[n]
print(w * h)

Java:

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int len = in.nextInt();
        Map<Long,Integer> map15 = new HashMap<>();
        Map<Long,Integer> map60 = new HashMap<>();
        map15.put(0L, 1);
        map60.put(0L, 1);
        
        long total = 0, result = 0;
        for(int i = 0; i < len; i++) {
            total += in.nextInt();
            long rem15 = total % 15;
            long rem60 = total % 60;
            result += map15.getOrDefault(rem15, 0);
            result -= map60.getOrDefault(rem60, 0);
            map15.put(rem15, map15.getOrDefault(rem15, 0) + 1);
            map60.put(rem60, map60.getOrDefault(rem60, 0) + 1);
        }
        System.out.println(result);
    }
}

题目三:LCA节点集计数

题目内容

最近公共祖先简称 LCA(Lowest Common Ancestor) 两个节点的最近公共祖先,就是这两个点的公共祖先里面离根最远的那个。

小基有一棵有根树,树的根节点为 1 号节点。定义 f ( i ) f(i) f(i) 是:LCA 为 i i i 的非空节点集个数,小基想知道 f ( 1 ) f(1) f(1) f ( n ) f(n) f(n) 的值。由于 f ( i ) f(i) f(i) 可能很大,因此你需要输出 f ( i ) f(i) f(i) 1 0 9 + 7 10^9+7 109+7 取模后的结果。

输入描述

第一行输入一个正整数 n n n,代表树的节点个数。

接下来 n − 1 n-1 n1 行,每行两个整数 u , v ( 1 ≤ u , v ≤ n ) u,v(1\le u,v \le n) u,v(1u,vn) 表示树上的边。

1 ≤ n ≤ 1 0 5 1≤ n ≤ 10^5 1n105

输出描述

输出 n n n 个整数表示答案。

样例1

输入:

3
1 2
2 3

输出:

4 2 1

说明:
LCA 为 1 的节点集:(1),(1,2),(1,3),(1,2,3)
LCA 为 2 的节点对:(2),(2,3)
LCA 为 3 的节点对:(3)

题解

对于当前节点 i i i,从该节点所有子树中选出一些点后构成的节点集合的 LCA 一定是节点 i i i。可以分两种情况:

  1. 选择节点 i i i:每棵子树可以任意选择(包括不选)
  2. 不选节点 i i i:不能只选一棵子树上的节点,且所有选择不能为空集

参考代码

C++:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;

ll fastPow(ll base, ll exp) {
    ll res = 1;
    while(exp) {
        if(exp & 1) res = res * base % MOD;
        base = base * base % MOD;
        exp >>= 1;
    }
    return res;
}

int main() {
    int n;
    cin >> n;
    vector<vector<int>> tree(n + 1);
    for(int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        tree[u].push_back(v);
        tree[v].push_back(u);
    }
    vector<ll> ans(n + 1);
    
    function<int(int,int)> dfs = [&](int node, int parent) {
        vector<int> sizes{1};
        int total = 1;
        for(int child : tree[node])
            if(child != parent) {
                int sz = dfs(child, node);
                sizes.push_back(sz);
                total += sz;
            }
        
        ll prod = 1, sum = 0;
        for(int i = 1; i < sizes.size(); i++) {
            ll tmp = fastPow(2, sizes[i], MOD);
            prod = prod * tmp % MOD;
            sum = (sum + tmp - 1 + MOD) % MOD;
        }
        ans[node] = (prod * 2 - sum + MOD) % MOD;
        return total;
    };
    
    dfs(1, -1);
    for(int i = 1; i <= n; i++) {
        cout << ans[i] << " ";
    }
    return 0;
}

Python:

def qpow(x, n, mod):
    res = 1
    while n:
        if n & 1:
            res = res * x % mod
        x = x * x % mod
        n >>= 1
    return res

n = int(input())
tree = [[] for _ in range(n + 1)]
for _ in range(n - 1):
    u, v = map(int, input().split())
    tree[u].append(v)
    tree[v].append(u)

mod = 10**9 + 7
ans = [0] * (n + 1)

def dfs(node, par):
    szs = [1]
    tot = 1
    for nxt in tree[node]:
        if nxt != par:
            sz = dfs(nxt, node)
            szs.append(sz)
            tot += sz
    
    prod, sm = 1, 0
    for i in range(1, len(szs)):
        tmp = qpow(2, szs[i], mod)
        prod = prod * tmp % mod
        sm = (sm + tmp - 1) % mod
    ans[node] = (prod * 2 - sm) % mod
    return tot

dfs(1, 0)
print(*ans[1:])

Java:

import java.util.*;
public class Main {
    static final int MOD = 1000000007;
    static ArrayList<Integer>[] graph;
    static long[] result;
    
    static long powMod(long base, long exp) {
        long ans = 1;
        while(exp > 0) {
            if((exp & 1) == 1) 
                ans = ans * base % MOD;
            base = base * base % MOD;
            exp >>= 1;
        }
        return ans;
    }
    
    static int dfs(int node, int parent) {
        ArrayList<Integer> sizes = new ArrayList<>();
        sizes.add(1);
        int total = 1;
        
        for(int next : graph[node]) {
            if(next != parent) {
                int size = dfs(next, node);
                sizes.add(size);
                total += size;
            }
        }
        
        long prod = 1, sum = 0;
        for(int i = 1; i < sizes.size(); i++) {
            long temp = powMod(2, sizes.get(i));
            prod = prod * temp % MOD;
            sum = (sum + temp - 1 + MOD) % MOD;
        }
        result[node] = (prod * 2 - sum + MOD) % MOD;
        return total;
    }
    
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        graph = new ArrayList[n + 1];
        result = new long[n + 1];
        
        for(int i = 0; i <= n; i++)
            graph[i] = new ArrayList<>();
            
        for(int i = 1; i < n; i++) {
            int u = scan.nextInt();
            int v = scan.nextInt();
            graph[u].add(v);
            graph[v].add(u);
        }
        
        dfs(1, 0);
        for(int i = 1; i <= n; i++)
            System.out.print(result[i] + " ");
    }
}

题目四:子数组权值和

题目内容

小基定义一个数组的权值为这个数组的最小值乘上数组的长度。小基现在有一个数组,他想知道这个数组的所有连续子数组的权值之和。

输入描述

第一行输入一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) n(1n105) 表示数组长度。

第二行输入 n n n 个整数表示数组 a i ( 1 ≤ a i ≤ 1 0 3 ) a_i(1\le a_i\le 10^3) ai(1ai103)

输出描述

一个整数。

样例1

输入:

2
1 2

输出:

5

说明:
子数组[1]的权值为 1 ∗ 1 = 1 1*1=1 11=1
子数组[2]的权值为 2 ∗ 1 = 2 2*1=2 21=2
子数组[1,2]的权值为 1 ∗ 2 = 2 1*2=2 12=2
因此所有子数组的权值之和为 1+2+2=5。

题解

使用单调栈来解决。对于每个元素,需要找到它左右两边第一个比它小的元素,这样就能确定以它为最小值的所有子数组。使用单调递增栈维护这个性质。

参考代码

C++:

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

int main() {
    int n;
    cin >> n;
    vector<int> arr(n + 2);
    for(int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    arr[n + 1] = INT_MIN;
    
    vector<int> stk;
    stk.push_back(0);
    ll ans = 0;
    
    for(int i = 1; i <= n + 1; i++) {
        while(stk.size() > 1 && arr[i] < arr[stk.back()]) {
            int pos = stk.back();
            stk.pop_back();
            int left = pos - stk.back();
            int right = i - pos;
            ll leftSum = 1LL * (1 + left) * left / 2;
            ll contrib = (leftSum + leftSum + 1LL * (right-1) * left) * right / 2;
            ans += 1LL * arr[pos] * contrib;
        }
        stk.push_back(i);
    }
    cout << ans << endl;
    return 0;
}

Python:

from collections import deque

n = int(input())
arr = [0] + list(map(int, input().split())) + [float('-inf')]
stk = deque([0])
ans = 0

for i in range(1, n + 2):
    while len(stk) > 1 and arr[i] < arr[stk[-1]]:
        pos = stk.pop()
        left = pos - stk[-1]
        rght = i - pos
        lsum = (1 + left) * left // 2
        cont = (lsum + lsum + (rght-1) * left) * rght // 2
        ans += arr[pos] * cont
    stk.append(i)

print(ans)

Java:

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int size = scan.nextInt();
        int[] data = new int[size + 2];
        for(int i = 1; i <= size; i++) {
            data[i] = scan.nextInt();
        }
        data[size + 1] = Integer.MIN_VALUE;
        
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(0);
        long total = 0;
        
        for(int idx = 1; idx <= size + 1; idx++) {
            while(stack.size() > 1 && data[idx] < data[stack.peek()]) {
                int curr = stack.pop();
                int lDist = curr - stack.peek();
                int rDist = idx - curr;
                long lSum = (long)(1 + lDist) * lDist / 2;
                long temp = (lSum + lSum + (long)(rDist-1) * lDist) * rDist / 2;
                total += (long)data[curr] * temp;
            }
            stack.push(idx);
        }
        System.out.println(total);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值