【笔试刷题】字节-2026.04.19-改编真题

✅ 春招备战指南 ✅

💡 学习建议:

  • 先尝试独立解题
  • 对照解析查漏补缺

🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。

🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力

🤖 内容包含AI辅助生成,题解和代码均经过多轮验证,有问题欢迎评论

🌸 目前本专栏已经上线200+套真题改编解析,后续会持续更新的

春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗

字节-2026.04.19

字节-2026.04.19

题目一:小兰的走廊按钮

这一题的关键在于先固定按钮持续时间,再去问“最少需要按几次”。固定后可以直接从左往右贪心覆盖第一个还没处理的关闭门,再利用可行性的单调性二分答案。

难度:Mid

题目二:小兰的印章网格

判断过程要围绕“一个合法图形一定能拆成若干个彼此不接触的 红块”展开。先找完整红块,再判相邻冲突,最后做一遍覆盖核验,三个步骤缺一不可。

难度:Mid

题目三:小兰的尾零字典序

操作虽然作用在整个数组上,但变化的是因子 的位置分布。字典序比较优先看前缀,所以应该从左到右尽量把前面的因子 拿走,并把代价统一丢到最后一个位置。

难度:Mid

题目四:小兰的第二大池化

题意就是标准模拟,没有隐藏状态。按层处理所有 小块,每块留下第二大值,直到矩阵缩成一个数即可。

难度:Low

1. 小兰的走廊按钮

问题描述

小兰需要沿着一条长度为 的走廊从左走到右,途中会依次经过编号为 的门。

扇门的状态用 表示:

  • ,表示这扇门原本就是开着的。
  • ,表示这扇门原本是关着的。

她手里有一个按钮,最多可以按下 次。

如果在准备通过某一扇门时按下按钮,并把持续时间设为 ,那么从当前门开始,接下来连续 扇门都会临时视为打开状态。由于每通过一扇门恰好花费 秒,所以这个持续时间恰好对应连续 扇门。

小兰想把持续时间设得尽量短。请你求出,为了顺利通过全部门,最小的非负整数 是多少。

输入格式

第一行输入一个整数 ,表示测试数据组数。

对于每组数据:

  • 第一行输入两个整数 ,分别表示门的数量和按钮最多使用次数。
  • 第二行输入 个整数 ,表示每扇门的初始状态。

输出格式

对于每组数据,输出一行一个整数,表示最小的可行持续时间

样例输入

3
5 1
0 1 1 0 1
7 2
1 0 1 1 0 1 0
4 2
0 0 0 0

样例输出

4
3
0

样例输入 2

1
6 2
1 1 0 0 1 1

样例输出 2

2

数据范围

  • 保证所有测试数据中

样例说明

样例 解释说明
样例 1 组数据里,若 ,从第 扇门按下按钮后只能覆盖到第 扇门,第 扇门仍然无法通过,所以最小值是 。第 组数据中所有门本来就打开,按钮一次都不用按,答案为
样例 2 可以在第 扇门和第 扇门前各按一次按钮,持续时间取 就能覆盖全部关闭门。

题解

先把持续时间 看成已经确定,问题会变成:

“至少要按几次按钮,才能让所有关闭门都被覆盖?”

1. 固定 后,最优策略是什么

从左到右扫描所有门。

如果当前门本来就是开的,或者已经被前一次按钮覆盖到了,那么直接继续往后走。

如果扫到的是当前最靠左、还没有被覆盖的关闭门,那么这一次按钮必须在这里按下。

原因很简单:

  • 按得更晚,当前这扇门已经过不去。
  • 按得更早,也不会让左边变得更好,因为左边已经处理完了。

所以固定 时,可以直接贪心:

  • 遇到第一个未覆盖的关闭门,就按一次按钮。
  • 这一按会覆盖当前位置开始的连续 扇门。
  • 然后把指针跳到覆盖区间之后,继续扫描。

这样扫完整条走廊,得到的就是固定 时所需的最少按键次数。

2. 为什么可以二分答案

如果某个持续时间 已经可行,那么任何更大的持续时间也一定可行。

因为每次按钮能覆盖的门只会更多,不会更少。

这说明“是否能在不超过 次内通过全部门”对 具有单调性,可以直接二分最小可行值。

3. 边界怎么处理

如果整条走廊里没有一扇关闭门,那么不需要按按钮,答案就是

否则答案一定在 之间,直接在这个区间上二分即可。

4. 复杂度分析

二分会做 次检查。

每次检查只需要线性扫一遍门,复杂度是

所以单组数据总复杂度为 ,可以通过题目范围。

  • Python
import sys

input = lambda: sys.stdin.readline().strip()

def chk(arr, x):
    n = len(arr)
    cnt = 0
    i = 0
    while i < n:
        # 原本就打开的门可以直接通过。
        if arr[i] == 0:
            i += 1
            continue

        # 这是最靠左、还没被覆盖的关闭门,
        # 这一按必须从这里开始。
        cnt += 1
        i += x
    return cnt

def solve():
    t = int(input())
    out = []

    for _ in range(t):
        n, k = map(int, input().split())
        arr = list(map(int, input().split()))

        # 全是开门时,持续时间取 0 就够了。
        if sum(arr) == 0:
            out.append("0")
            continue

        l, r = 1, n
        ans = n
        while l <= r:
            mid = (l + r) // 2
            if chk(arr, mid) <= k:
                ans = mid
                r = mid - 1
            else:
                l = mid + 1

        out.append(str(ans))

    print("\n".join(out))

if __name__ == "__main__":
    solve()
  • Cpp
#include <bits/stdc++.h>
using namespace std;

int need(const vector<int>& arr, int x) {
    int n = (int)arr.size();
    int cnt = 0;

    for (int i = 0; i < n; ) {
        // 开门可以直接通过。
        if (arr[i] == 0) {
            ++i;
            continue;
        }

        // 这是最靠左的未覆盖关闭门,
        // 按钮必须从这里开始生效。
        ++cnt;
        i += x;
    }

    return cnt;
}

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

    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;

        vector<int> arr(n);
        int sum = 0;
        for (int i = 0; i < n; ++i) {
            cin >> arr[i];
            sum += arr[i];
        }

        // 没有关闭门时,答案就是 0。
        if (sum == 0) {
            cout << 0 << "\n";
            continue;
        }

        int l = 1, r = n, ans = n;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (need(arr, mid) <= k) {
                ans = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }

        cout << ans << "\n";
    }
    return 0;
}
  • Java
import java.io.*;
import java.util.*;

public class Main {
    static int need(int[] arr, int x) {
        int n = arr.length;
        int cnt = 0;

        for (int i = 0; i < n; ) {
            // 开门不需要额外处理。
            if (arr[i] == 0) {
                i++;
                continue;
            }

            // 当前最靠左的未覆盖关闭门,
            // 只能从这里开始按按钮。
            cnt++;
            i += x;
        }

        return cnt;
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int t = Integer.parseInt(br.readLine().trim());
        StringBuilder out = new StringBuilder();

        while (t-- > 0) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int n = Integer.parseInt(st.nextToken());
            int k = Integer.parseInt(st.nextToken());

            st = new StringTokenizer(br.readLine());
            int[] arr = new int[n];
            int sum = 0;
            for (int i = 0; i < n; i++) {
                arr[i] = Integer.parseInt(st.nextToken());
                sum += arr[i];
            }

            // 全部已经打开时,最优持续时间就是 0。
            if (sum == 0) {
                out.append(0).append('\n');
                continue;
            }

            int l = 1, r = n, ans = n;
            while (l <= r) {
                int mid = (l + r) >>> 1;
                if (need(arr, mid) <= k) {
                    ans = mid;
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            }

            out.append(ans).append('\n');
        }

        System.out.print(out);
    }
}

2. 小兰的印章网格

问题描述

小兰有一枚固定大小为 的印章。每按一次印章,对应的 子矩阵都会被全部染成红色。

她在一张 的网格上按下了若干次印章,并且整个过程始终满足两条规则:

  • 每个格子至多被染色一次。
  • 任意两个红色 块都不能相邻。这里的相邻指两块红色区域只要共用一条边,或者只共用一个角,都算相邻。

现在只知道最终得到的矩阵:

  • * 表示这个格子是红色。
  • . 表示这个格子没有被染色。

请你判断,这个最终矩阵是否可能由上述过程得到。

共有 组询问。

输入格式

第一行输入一个整数 ,表示询问组数。

对于每组数据:

  • 第一行输入两个整数 ,表示网格的行数和列数。
  • 接下来输入 行,每行是一个长度为 的字符串,只包含 *.

输出格式

对于每组数据输出一行。

  • 如果这个矩阵合法,输出 Yes
  • 否则输出 No

样例输入

3
6 7
**...**
**...**
.......
.......
**...**
**...**
4 6
**....
**....
..**..
..**..
3 4
.**.
.**.
....

样例输出

Yes
No
Yes

样例输入 2

2
1 5
.*.*.
2 3
***
***

样例输出 2

No
No

数据范围

样例说明

样例 解释说明
样例 1 组数据里有四个彼此完全分开的 红块,所以合法。第 组数据中两块红色区域会在角上接触,不满足题意。第 组数据恰好是一枚单独的印章。
样例 2 组数据连一枚完整的 印章都放不下。第 组数据会产生两个互相重叠的候选印章位置,也不合法。

题解

这一题只需要判断最终图形能否拆成若干块互不接触的 红块。

1. 合法印章留下来的样子

一次印章会把一个完整的 区域染红。

所以只要某个图形是合法答案,那么其中每一个红色格子都必须属于某个完整的 红块。

这给出了第一步做法:

  • 枚举所有左上角位置。
  • 找出所有四个格子全为 * 红块。

2. 怎么判断这些红块会不会互相接触

设两个候选红块的左上角分别是

由于每个红块固定都是 ,只要同时满足:

这两块就一定会出现下面某一种情况:

  • 重叠;
  • 共边;
  • 只共角。

这些情况全都不允许。

反过来,只要行差或列差有一个超过 ,两块之间就至少隔开了一整行或一整列,不会互相接触。

因此可以把每个候选红块的左上角记下来,再检查周围 的左上角范围里有没有别的候选块。

3. 为什么最后还要做一次覆盖检查

找到候选红块并且确认它们彼此不接触后,事情还没结束。

因为原矩阵里可能还会残留某些 *,它们并不属于任何完整的 红块。

这类格子不可能通过合法印章得到。

所以还需要把所有候选红块覆盖到一张辅助表上,再扫描原矩阵:

  • 如果某个 * 没有被覆盖到,答案就是 No
  • 只有所有 * 都恰好属于某个合法红块时,答案才是 Yes

4. 特殊情况

如果 ,连一枚印章都放不下。

这时只有“整个矩阵全是 .”才合法,只要出现一个 * 就一定不合法。

5. 复杂度分析

枚举所有 子矩阵是

每个候选块只检查常数个相邻位置,最后覆盖检查也是

所以单组数据总复杂度为

  • Python
import sys

input = lambda: sys.stdin.readline().strip()

def solve():
    t = int(input())
    out = []

    for _ in range(t):
        n, m = map(int, input().split())
        g = [input() for _ in range(n)]

        # 行或列不足 2 时,根本放不下印章。
        if n < 2 or m < 2:
            ok = True
            for i in range(n):
                for j in range(m):
                    if g[i][j] == '*':
                        ok = False
            out.append("Yes" if ok else "No")
            continue

        pos = []
        has = [[False] * m for _ in range(n)]

        # 先找出所有完整的 2x2 红块。
        for i in range(n - 1):
            for j in range(m - 1):
                if g[i][j] == '*' and g[i + 1][j] == '*' and \
                   g[i][j + 1] == '*' and g[i + 1][j + 1] == '*':
                    pos.append((i, j))
                    has[i][j] = True

        ok = True

        # 两个左上角只要同时落在 5x5 邻域内,
        # 两块红色区域就一定会接触。
        for x, y in pos:
            for dx in range(-2, 3):
                for dy in range(-2, 3):
                    if dx == 0 and dy == 0:
                        continue
                    nx = x + dx
                    ny = y + dy
                    if 0 <= nx < n and 0 <= ny < m and has[nx][ny]:
                        ok = False
                        break
                if not ok:
                    break
            if not ok:
                break

        if not ok:
            out.append("No")
            continue

        cov = [[False] * m for _ in range(n)]
        for x, y in pos:
            for dx in range(2):
                for dy in range(2):
                    cov[x + dx][y + dy] = True

        # 每个红格都必须被某个合法印章覆盖到。
        for i in range(n):
            for j in range(m):
                if g[i][j] == '*' and not cov[i][j]:
                    ok = False
                    break
            if not ok:
                break

        out.append("Yes" if ok else "No")

    print("\n".join(out))

if __name__ == "__main__":
    solve()
  • Cpp
#include <bits/stdc++.h>
using namespace std;

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

    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        vector<string> g(n);
        for (int i = 0; i < n; ++i) {
            cin >> g[i];
        }

        // 尺寸太小时,合法情况只能是全白矩阵。
        if (n < 2 || m < 2) {
            bool ok = true;
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
          

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

互联网刷题笔试宝典 文章被收录于专栏

互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力

全部评论

相关推荐

3.19申请4.15笔试,200分及格分,240多通过4.23早上专业一面&nbsp;&nbsp;1小时左右自我介绍笔试复盘(自己提前准备,两道编程题错在哪里,为什么会出错自己考完笔试就可以先复盘一下)项目拷打(这方面问的非常细,包括项目的成员构成,整个项目的介绍,对于使用到的技术的了解程度以及假设出现了某个问题应该怎么改进。我的项目距离现在有一段时间了,一些比较细节的东西记不太清楚了,不过运气比较好,面试官提到的大多数问题都是我当时做项目的时候有遇到或者思考过的,所以印象相对深刻)一些AI相关的八股(AIagent)一道手撕题(后来我自己复盘发现我的算法并不完美,但是能够解释测例,也还凑合)4.23下午主管面试&nbsp;&nbsp;30分钟左右自我介绍项目介绍(问的比早上要深,包括使用的技术栈和对其它技术栈有多少了解)对前沿AI发展和AI模型框架的认识其它内容的了解,比赛,居住地,期望入职时间之类的总结:感觉华为比较注重就是实践方面,所以项目经历比较丰富或者对项目的各个方面了解比较深的同学是比较有优势的。笔试方面多刷题应该问题不大,我备考的时候牛客上所有套题基本都刷了两三遍(刷到麻了);面试的话应该就着重项目吧,使用的技术、算法原理什么的要多了解一点然后面试表现得自然一些问题应该不大;八股有,但是基本上点到为止,而且偏机器学习和前沿AI相关的多。主管面我当时是比较紧张,不过主管人很好,整个过程基本上是以一个交流分享的状态进行的。后续是怎么个流程,这样子是能成功入职了还是有其它环节我暂时也不清楚了,但是自己能把握的部分已经全部通过了,剩下的看造化了。希望能对各位求职有帮助。
查看7道真题和解析
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
04-11 20:49
先说bg:中九本,一段小厂实习,一段比较有名的中厂实习从暑期实习开始,我的求职之路就没有顺畅过,虽然当时已经做了hot100加一些常见算法题,约到的面试也是寥寥无几,参加的一些面试也都不太理想,就决定直接学习参加秋招秋招投了大概有五六百家,笔试面试都还是不少,但是过面的少之又少,有些聊的很开心的面试,第二天就是流程终止,那段时间真的很焦虑,但也并不算毫无收获,神州信息offer,思特奇offer,新凯来和华为都进了池子,原本是打算签一个保底,但是思特奇hr说薪资下来但是hc满了,华为接口人也说泡出来几率不小,于是就打算再等等,并总结了一下,自己的实习履历可能不够丰富,于是找了一个中厂去实习,实习到今年二月,华为是泡死了,接口人从一月份开始发消息就根本不回,在我面试的时候天天秒回,但是我心态还是算还好,因为我觉得加上这段实习,到春招应该可以拿到自己想要的offer从春招开始,我就一直在不停的投简历,并且笔试面试,刚开始进展还不错,有很多公司都到了二面,并且还有一个大厂面试都过了去泡池子,我本以为我的春招之路会一帆风顺,但紧接而来的是很多大厂的简历挂,以及四月份几乎没有什么面试,但我的心态还是比较良好,在完善自己的不足并且多去了解了解agent相关的知识,因为面试官经常会问到,但是就在今天,唯一入池的大厂发了感谢信,去看其他家也大部分流程挂了,我的对象还要被家里人逼着签一个我们老家的国企,如果签了,我和她以后就没有什么可能了,我不知道以后还是否可以保持现在的心态,努力了一年,结果还是要毕业即失业,我不知道怎么面对我的家人和朋友,今天可能真的是我21年来最绝望的一天了,我说这些并不是想制造焦虑,只是想发泄一下情绪,有些东西只有说出来才会好受点,希望牛油们见谅
漫步清风:看到中九的都这么难,我有点儿原谅自己了,我也是相当的难,我都没offer。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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