华为笔试 华为笔试题 0827

笔试时间:2025年8月27日

往年笔试合集:

2023春招秋招笔试合集

2024春招秋招笔试合集

第一题:冬季暖系统温度稳定性分析

某小区宣传其在冬季采暖期间,提供室内温度保持在18 - 24摄氏度之间,且温差在4摄氏度内的恒温服务。为了评价该小区冬季采暖温控效果,现按固定时间间隔对室内温度进行连续N次采样,采样的室内温度按照从0开始升序的索引号依次记录。通过计算采样的室内温度在小区承诺恒温范围内的持续时间,即持续时间内的采样室内温度值T均满足18<= T <= 24 ,且持续时间内的温差(最大温度max - 最低温度min)<=4,持续时间越长,采暖温控效果越好。请输出最大的持续时间开始点和结束点的采样的室内温度索引号,如果存在多个最大持续时间,按持续时间的开始点采样的室内温度索引号升序,逐行输出。

解答要求:

时间限制: C/C++ 1000ms,其他语言: 2000ms

内存限制: C/C++ 256MB,其他语言: 512MB

输入描述

第一行输入为按固定时间间隔对室内温度进行连续采样次N。

第二行输入为按固定时间间隔采集的一段连续的室内温度数值,整型,温度数值取值范围[0, 30]。

输入格式为:用空格分割的温度数值数组输出描述

输出描述

最大持续时间的开始点和结束点的数组元素索引号,中间用空格分隔。存在多组时逐行输出。

说明:数组元素索引号从0开始。

样例输入

6

16 18 20 25 23 20

样例输出

1 2

4 5

解释:满足恒温要求的为数组索引1 - 2、数组索引4 - 5,按起始索引升序输出

参考题解

这道题的思路是使用 滑动窗口 结合 单调队列 来解决。核心思想题目要求找到最长的连续子数组,满足两个条件:子数组中所有温度值都在 [18,24] 之间。子数组中的最大值与最小值的差值不大于 4。由于需要找到最长的子数组,并且要遍历所有可能的子数组,一个高效的方法就是使用滑动窗口。解题步骤定义滑动窗口:我们使用两个指针 L 和 R 来定义一个窗口 [L,R]。R 指针向右移动,不断扩大窗口,而 L 指针在不满足条件时向右移动,缩小窗口。处理温度范围:当 R 指针指向的温度值 T 不在 [18,24] 范围内时,这个 T 肯定不能成为合格子数组的一部分。因此,当前窗口从 L 到 R 都不可能满足条件。我们直接将 L 指针移动到 R+1 的位置,并清空记录窗口内最大最小值的辅助数据结构,重新开始一个新的窗口。处理温差:当 R 指针指向的温度值在 [18,24] 范围内时,我们需要判断当前窗口 [L,R] 是否满足温差 ≤4 的条件。为了快速获取窗口内的最大值和最小值,我们使用两个 单调队列。一个 单调递增队列 记录窗口内最小值的索引(q_min)。队头始终是当前窗口的最小值索引。一个 单调递减队列 记录窗口内最大值的索引(q_max)。队头始终是当前窗口的最大值索引。维护单调队列:每当 R 向右移动,将新的温度值添加到单调队列中。为了保持队列的单调性,需要移除队列尾部不符合单调性要求的元素。为了确保队头元素始终在当前窗口内,当 L 向右移动时,需要检查队头元素的索引是否等于 L。如果是,将其从队列头部移除。更新结果:在每次 R 指针移动后,检查当前窗口 [L,R] 是否满足所有条件(即温度在 [18,24] 且温差 ≤4)。如果温差大于 4,则说明当前窗口不满足条件,需要移动 L 指针来缩小窗口,直到温差再次 ≤4。每次 L 和 R 移动后,如果当前窗口的长度大于之前记录的最大长度,则更新最大长度并清空结果列表,将当前窗口 [L,R] 加入结果。如果当前窗口的长度等于最大长度,则将当前窗口 [L,R] 添加到结果列表中。通过这种方式,我们可以在 O(N) 的时间复杂度内解决问题,因为每个元素最多被 L 和 R 遍历一次,并最多进入和离开单调队列一次。

C++:

#include <iostream>
#include <vector>
#include <deque>

using namespace std;

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

    int best = 0;
    vector<pair<int, int>> ans;
    int L = 0;
    deque<int> q_min, q_max;

    for (int R = 0; R < n_val; ++R) {
        int t = arr[R];

        // 如果当前元素不在18-24范围内,重置窗口
        if (!(t >= 18 && t <= 24)) {
            L = R + 1;
            q_min.clear();
            q_max.clear();
            continue;
        }

        // 维护最大值队列(单调递减)
        while (!q_max.empty() && arr[q_max.back()] <= t) {
            q_max.pop_back();
        }
        q_max.push_back(R);

        // 维护最小值队列(单调递增)
        while (!q_min.empty() && arr[q_min.back()] >= t) {
            q_min.pop_back();
        }
        q_min.push_back(R);

        // 确保当前窗口中最大值与最小值的差不超过4
        while (arr[q_max.front()] - arr[q_min.front()] > 4) {
            if (q_min.front() == L) {
                q_min.pop_front();
            }
            if (q_max.front() == L) {
                q_max.pop_front();
            }
            L++;
        }

        // 更新最长子数组信息
        int cur_len = R - L + 1;
        if (cur_len > best) {
            best = cur_len;
            ans.clear();
            ans.emplace_back(L, R);
        } else if (cur_len == best && best > 0) {
            if (ans.empty() || ans.back() != make_pair(L, R)) {
                ans.emplace_back(L, R);
            }
        }
    }

    // 输出结果
    for (const auto& p : ans) {
        cout << p.first << " " << p.second << endl;
    }

    return 0;
}

Java:

import java.util.*;
import java.io.*;

public class RangeSubarrayFinder {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int nVal = Integer.parseInt(br.readLine());
        int[] arr = new int[nVal];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i < nVal; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }

        int best = 0;
        List<int[]> ans = new ArrayList<>();
        int L = 0;
        Deque<Integer> qMin = new ArrayDeque<>();
        Deque<Integer> qMax = new ArrayDeque<>();

        for (int R = 0; R < nVal; R++) {
            int t = arr[R];

            // 如果当前元素不在18-24范围内,重置窗口
            if (!(t >= 18 && t <= 24)) {
                L = R + 1;
                qMin.clear();
                qMax.clear();
                continue;
            }

            // 维护最大值队列(单调递减)
            while (!qMax.isEmpty() && arr[qMax.peekLast()] <= t) {
                qMax.pollLast();
            }
            qMax.offerLast(R);

            // 维护最小值队列(单调递增)
            while (!qMin.isEmpty() && arr[qMin.peekLast()] >= t) {
                qMin.pollLast();
            }
            qMin.offerLast(R);

            // 确保当前窗口中最大值与最小值的差不超过4
            while (arr[qMax.peekFirst()] - arr[qMin.peekFirst()] > 4) {
                if (qMin.peekFirst() == L) {
                    qMin.pollFirst();
                }
                if (qMax.peekFirst() == L) {
                    qMax.pollFirst();
                }
                L++;
            }

            // 更新最长子数组信息
            int curLen = R - L + 1;
            if (curLen > best) {
                best = curLen;
                ans.clear();
                ans.add(new int[]{L, R});
            } else if (curLen == best && best > 0) {
                if (ans.isEmpty() || !Arrays.equals(ans.get(ans.size() - 1), new int[]{L, R})) {
                    ans.add(new int[]{L, R});
                }
            }
        }

        // 输出结果
        for (int[] pair : ans) {
            System.out.println(pair[0] + " " + pair[1]);
        }
    }
}

Python:

import sys
from collections import deque as dq


def main():
    n_val = int(sys.stdin.readline())
    arr = list(map(int, sys.stdin.readline().split()))

    best = 0
    ans = []
    L = 0
    q_min = dq()
    q_max = dq()

    for R in range(n_val):
        t = arr[R]

        ifnot (18 <= t <= 24):
            L = R + 1
            q_min.clear()
            q_max.clear()
            continue

        while q_max and arr[q_max[-1]] <= t:
            q_max.pop()
        q_max.append(R)

        while q_min and arr[q_min[-1]] >= t:
            q_min.pop()
        q_min.append(R)

        while arr[q_max[0]] - arr[q_min[0]] > 4:
            if q_min[0] == L:
                q_min.popleft()
            if q_max[0] == L:
                q_max.popleft()
            L += 1

        cur_len = R - L + 1
        if cur_len > best:
            best = cur_len
            ans = [(L, R)]
        elif cur_len == best and best > 0:
            ifnot ans or ans[-1] != (L, R):
                ans.append((L, R))

    for a, b in ans:
        print(a, b)


if __name__ == '__main__':
    main()

第二题:樱桃等级筛选

某大型樱桃加工厂使用自动化机械扫描了一批樱桃的尺寸大小。现在获得了直径范围 [L,H] 各个区间所有的樱桃个数统计。现在需要通过 m 个等级(m < H - L)来筛选不同尺寸大小的樱桃,筛选后需使得各等级内的樱桃数目的标准差最小。

输入描述

第一行输入两个数字,第一个数字表示樱桃的总组数 n(2 < n ≤ 20),第二个数字 m 表示需要获取的等级数目 a,2 < a < n。

第二行输入一个长度为 H - L + 1 的数列 A,a <H - L + 1,其中的第 i 个元素 a_i 表示直径为 L + i 樱桃个数(i ∈ [0,H - L]),0 < a_i < 100。

输出描述

输出长度为 m 的数列 B,

其中的第 1 个元素 b₀表示顺序从 A 中取 b₀个元素,将该尺寸范围内的樱桃作为一个分类等级;

第 2 个元素 b₁表示顺序从 A 中起始点 b₀开始取 b₁个元素,将该尺寸范围内的樱桃作为一个分类等级,依次类推。

样例输入

10 4

16 40 37 20 18 30 18 60 50 37

样例输出

3 3 2 2

参考题解

这道题的核心是组合优化问题,即在所有可能的分类方案中,找到能使标准差最小的那一种。核心思想题目要求将一个长度为 N 的数组分成 M 个连续的子数组,使得这 M 个子数组的和(代表每个等级的樱桃总数)的标准差最小。由于 N 的范围非常小(N≤20),我们可以考虑使用暴力穷举或深度优先搜索(DFS)来遍历所有可能的分割方案。解题步骤确定搜索空间:我们需要将 N 个樱桃尺寸组,分成 M 个连续的等级。一个等级至少包含一个尺寸组。我们可以用一个递归函数(DFS)来尝试所有可能的分割点。递归函数的设计:定义一个 dfs(pos, left, s_list, l_list) 函数。pos: 当前处理的起始位置,即从 A[pos] 开始。left: 还需要分成的等级数。s_list: 存储当前分割方案中,每个等级的樱桃总数。l_list: 存储当前分割方案中,每个等级包含的尺寸组个数。递归的终止条件:当 left 为 0 时,说明我们已经成功将所有樱桃分成了 M 个等级。此时,我们计算 s_list 中所有元素的标准差。如果这个标准差小于我们当前记录的最小值 g_min,则更新 g_min,并记录当前的分割方案 l_list 到 g_res 中。递归的剪枝:为了提高效率,我们可以加入剪枝条件。if N - pos < left: 如果剩余的樱桃组数量小于我们还需要分的等级数,那么无论如何都无法完成分割,直接返回。递归的遍历:在函数内部,我们从当前位置 pos 开始,遍历所有可能的子数组长度,作为当前等级。for j in range(pos, N - left + 1):这个循环控制了当前等级的结束位置 j。对于每一个结束位置 j,我们计算当前等级的樱桃总数,并将其添加到 s_list 中。同时,将当前等级的长度 j - pos + 1 添加到 l_list 中。然后,我们递归调用 dfs(j + 1, left - 1, s_list, l_list),继续处理剩下的樱桃组。递归返回后,我们需要回溯,将

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

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

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

全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

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