当前位置: 首页 > article >正文

【2024年华为OD机试】(A卷,200分)- 优雅子数组 (JavaScriptJava PythonC/C++)

在这里插入图片描述

一、问题描述

题目描述

如果一个数组中出现次数最多的元素出现大于等于 k 次,被称为 k-优雅数组k 也可以被称为优雅阈值。

例如:

  • 数组 [1, 2, 3, 1, 2, 3, 1] 是一个 3-优雅数组,因为元素 1 出现次数大于等于 3 次。
  • 数组 [1, 2, 3, 1, 2] 不是一个 3-优雅数组,因为其中出现次数最多的元素是 12,只出现了 2 次。

给定一个数组 Ak,请求出 A 有多少子数组是 k-优雅子数组

子数组是数组中一个或多个连续元素组成的数组。

例如,数组 [1, 2, 3, 4] 包含 10 个子数组,分别是:

  • [1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [2], [2, 3], [2, 3, 4], [3], [3, 4], [4]

输入描述

  • 第一行输入两个数字,以空格隔开,含义是:A 数组长度 k 值。
  • 第二行输入 A 数组元素,以空格隔开。

输出描述

输出 A 有多少子数组是 k-优雅子数组


用例

用例 1

输入:

7 3
1 2 3 1 2 3 1

输出:

1

说明:

  • 只有子数组 [1, 2, 3, 1, 2, 3, 1]3-优雅子数组

用例 2

输入:

7 2
1 2 3 1 2 3 1

输出:

10

说明:

  • 有多个子数组满足 2-优雅子数组 的条件。

题目解析

解题思路

  1. 暴力枚举法

    • 使用双指针(双重 for 循环)枚举所有子数组。
    • 外层指针 i 指向子数组左边界,内层指针 j 指向子数组右边界。
    • 统计每个子数组内部各数字的出现次数,若某个数字出现次数大于等于 k,则该子数组符合要求,统计结果 ans++
  2. 优化思路

    • 暴力枚举法的时间复杂度为 O(n^2),对于大规模数据会超时。
    • 优化点:
      • 使用 滑动窗口 的思想,减少重复统计。
      • 当找到一个符合要求的子数组后,右指针 j 不需要回退,而是继续向右移动。
      • 左指针 i 右移时,更新统计结果,避免重复计算。
  3. 滑动窗口优化

    • 使用一个哈希表(或数组)记录当前窗口内各数字的出现次数。
    • 当某个数字的出现次数达到 k 时,记录当前窗口的贡献值(即从当前右边界到数组末尾的所有子数组都符合要求)。
    • 左指针 i 右移时,更新哈希表,并检查是否仍然满足条件。
  4. 边界条件

    • 当左指针 i 右移时,需要减少左边界元素的计数。
    • 当右指针 j 右移时,需要增加右边界元素的计数。
    • 确保每次移动指针后,窗口内的统计结果正确。

双指针运动逻辑

  1. 初始状态

    • 左指针 l = 0,右指针 r = 0
    • 哈希表 count 记录当前窗口内各数字的出现次数。
  2. 右指针移动

    • 将右指针 r 指向的元素加入窗口,并更新哈希表。
    • 若某个数字的出现次数达到 k,则记录当前窗口的贡献值。
  3. 左指针移动

    • 当窗口内某个数字的出现次数超过 k 时,左指针 l 右移。
    • 减少左边界元素的计数,并更新哈希表。
  4. 贡献值计算

    • 当找到一个符合要求的子数组时,从当前右边界到数组末尾的所有子数组都符合要求。
    • 贡献值为 n - r,其中 n 是数组长度。

示例分析

以输入 7 2 和数组 [1, 2, 3, 1, 2, 3, 1] 为例:

  1. 初始状态

    • l = 0, r = 0
    • 窗口为 [1]count = {1: 1}
  2. 右指针移动

    • r = 1,窗口为 [1, 2]count = {1: 1, 2: 1}
    • r = 2,窗口为 [1, 2, 3]count = {1: 1, 2: 1, 3: 1}
    • r = 3,窗口为 [1, 2, 3, 1]count = {1: 2, 2: 1, 3: 1}
    • 此时 1 的出现次数达到 2,贡献值为 7 - 3 = 4
  3. 左指针移动

    • l = 1,窗口为 [2, 3, 1]count = {1: 1, 2: 1, 3: 1}
    • r = 4,窗口为 [2, 3, 1, 2]count = {1: 1, 2: 2, 3: 1}
    • 此时 2 的出现次数达到 2,贡献值为 7 - 4 = 3
  4. 继续移动

    • 重复上述过程,直到右指针 r 到达数组末尾。

总结

  • 通过滑动窗口优化,减少重复统计,时间复杂度降低到 O(n)
  • 使用哈希表记录窗口内各数字的出现次数,确保统计结果正确。
  • 每次找到符合要求的子数组后,计算贡献值并累加到结果中。

二、JavaScript算法源码

以下是代码的详细注释和讲解,帮助理解每一部分的作用和逻辑:


代码讲解

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

// 创建 readline 接口,用于从控制台读取输入
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

// 定义数组 lines,用于存储输入的行数据
const lines = [];
// 定义变量 n 和 k,分别表示数组长度和优雅阈值
let n, k;

// 监听 'line' 事件,当用户输入一行内容时触发
rl.on("line", (line) => {
  // 将输入的行数据存入 lines 数组
  lines.push(line);

  // 当 lines 数组中有两行数据时,表示输入完成
  if (lines.length === 2) {
    // 解析第一行输入,获取数组长度 n 和优雅阈值 k
    [n, k] = lines[0].split(" ").map(Number);
    // 解析第二行输入,获取数组 arr
    const arr = lines[1].split(" ").map(Number);
    // 调用 getResult 函数,计算 k-优雅子数组的数量,并输出结果
    console.log(getResult(arr, n, k));
    // 清空 lines 数组,以便处理下一组输入
    lines.length = 0;
  }
});

// 定义 getResult 函数,用于计算 k-优雅子数组的数量
function getResult(arr, n, k) {
  // 初始化变量 ans,用于记录 k-优雅子数组的数量
  let ans = 0;

  // 初始化双指针 l 和 r,分别表示滑动窗口的左边界和右边界
  let l = 0;
  let r = 0;

  // 定义对象 count,用于记录滑动窗口内各数字的出现次数
  const count = {};

  // 使用滑动窗口遍历数组
  while (l < n && r < n) {
    // 获取右指针 r 指向的数组元素
    const c = arr[r];

    // 更新当前数字 c 的出现次数
    count[c] ? count[c]++ : (count[c] = 1);

    // 如果当前数字 c 的出现次数达到 k 次
    if (count[c] >= k) {
      // 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求
      ans += n - r;

      // 左指针 l 右移一格,减少左边界元素的计数
      count[arr[l]]--;
      l++;

      // 右指针 r 左移一格,回退到上一个位置
      count[c]--;
      r--;
    }

    // 右指针 r 右移一格,继续扩展窗口
    r++;
  }

  // 返回最终找到的 k-优雅子数组的数量
  return ans;
}

代码逻辑详解

  1. 输入处理:

    • 使用 readline 模块从控制台读取输入。
    • 将输入的两行数据分别解析为数组长度 n、优雅阈值 k 和数组 arr
  2. 滑动窗口初始化:

    • 定义双指针 lr,分别表示滑动窗口的左边界和右边界,初始值均为 0。
    • 定义对象 count,用于记录滑动窗口内各数字的出现次数。
  3. 滑动窗口遍历:

    • 使用 while 循环遍历数组,右指针 r 从 0 开始逐步向右移动。
    • 对于每个右指针 r 指向的元素 c,更新其在 count 中的出现次数。
  4. 判断是否符合条件:

    • 如果当前数字 c 的出现次数达到 k 次,则:
      • 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求,贡献值为 n - r
      • 左指针 l 右移一格,减少左边界元素的计数。
      • 右指针 r 左移一格,回退到上一个位置。
  5. 右指针移动:

    • 右指针 r 右移一格,继续扩展窗口。
  6. 返回结果:

    • 遍历结束后,返回 ans,即 k-优雅子数组的数量。

示例运行

以输入 7 2 和数组 [1, 2, 3, 1, 2, 3, 1] 为例:

  1. 初始状态:

    • l = 0, r = 0
    • 窗口为 [1]count = {1: 1}
  2. 右指针移动:

    • r = 1,窗口为 [1, 2]count = {1: 1, 2: 1}
    • r = 2,窗口为 [1, 2, 3]count = {1: 1, 2: 1, 3: 1}
    • r = 3,窗口为 [1, 2, 3, 1]count = {1: 2, 2: 1, 3: 1}
    • 此时 1 的出现次数达到 2 次,贡献值为 7 - 3 = 4
  3. 左指针移动:

    • l = 1,窗口为 [2, 3, 1]count = {1: 1, 2: 1, 3: 1}
    • r = 4,窗口为 [2, 3, 1, 2]count = {1: 1, 2: 2, 3: 1}
    • 此时 2 的出现次数达到 2 次,贡献值为 7 - 4 = 3
  4. 继续移动:

    • 重复上述过程,直到右指针 r 到达数组末尾。

总结

  • 该代码通过滑动窗口的方法,高效地统计了数组中所有 k-优雅子数组的数量。
  • 使用双指针和哈希表记录窗口内各数字的出现次数,确保统计结果正确。
  • 每次找到符合要求的子数组后,计算贡献值并累加到结果中,避免了重复计算。

三、Java算法源码

以下是 Java 代码的详细注释和讲解,帮助理解每一部分的作用和逻辑:


代码讲解

import java.util.HashMap;
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    // 创建 Scanner 对象,用于从控制台读取输入
    Scanner sc = new Scanner(System.in);

    // 读取数组长度 n 和优雅阈值 k
    int n = sc.nextInt();
    int k = sc.nextInt();

    // 定义数组 arr,用于存储输入的数组元素
    Integer[] arr = new Integer[n];
    for (int i = 0; i < n; i++) {
      arr[i] = sc.nextInt();
    }

    // 调用 getResult 方法,计算 k-优雅子数组的数量,并输出结果
    System.out.println(getResult(arr, n, k));
  }

  public static Integer getResult(Integer[] arr, Integer n, Integer k) {
    // 初始化变量 ans,用于记录 k-优雅子数组的数量
    int ans = 0;

    // 初始化双指针 l 和 r,分别表示滑动窗口的左边界和右边界
    int l = 0;
    int r = 0;

    // 定义 HashMap count,用于记录滑动窗口内各数字的出现次数
    HashMap<Integer, Integer> count = new HashMap<>();

    // 使用滑动窗口遍历数组
    while (l < n && r < n) {
      // 获取右指针 r 指向的数组元素
      Integer c = arr[r];

      // 更新当前数字 c 的出现次数
      count.put(c, count.getOrDefault(c, 0) + 1);

      // 如果当前数字 c 的出现次数达到 k 次
      if (count.get(c) >= k) {
        // 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求
        ans += n - r;

        // 左指针 l 右移一格,减少左边界元素的计数
        count.put(arr[l], count.get(arr[l]) - 1);
        l++;

        // 右指针 r 左移一格,回退到上一个位置
        count.put(c, count.get(c) - 1);
        r--;
      }

      // 右指针 r 右移一格,继续扩展窗口
      r++;
    }

    // 返回最终找到的 k-优雅子数组的数量
    return ans;
  }
}

代码逻辑详解

  1. 输入处理:

    • 使用 Scanner 从控制台读取输入的数组长度 n 和优雅阈值 k
    • 读取数组 arr 的元素并存储到 Integer[] 数组中。
  2. 滑动窗口初始化:

    • 定义双指针 lr,分别表示滑动窗口的左边界和右边界,初始值均为 0。
    • 定义 HashMap 对象 count,用于记录滑动窗口内各数字的出现次数。
  3. 滑动窗口遍历:

    • 使用 while 循环遍历数组,右指针 r 从 0 开始逐步向右移动。
    • 对于每个右指针 r 指向的元素 c,更新其在 count 中的出现次数。
  4. 判断是否符合条件:

    • 如果当前数字 c 的出现次数达到 k 次,则:
      • 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求,贡献值为 n - r
      • 左指针 l 右移一格,减少左边界元素的计数。
      • 右指针 r 左移一格,回退到上一个位置。
  5. 右指针移动:

    • 右指针 r 右移一格,继续扩展窗口。
  6. 返回结果:

    • 遍历结束后,返回 ans,即 k-优雅子数组的数量。

示例运行

以输入 7 2 和数组 [1, 2, 3, 1, 2, 3, 1] 为例:

  1. 初始状态:

    • l = 0, r = 0
    • 窗口为 [1]count = {1: 1}
  2. 右指针移动:

    • r = 1,窗口为 [1, 2]count = {1: 1, 2: 1}
    • r = 2,窗口为 [1, 2, 3]count = {1: 1, 2: 1, 3: 1}
    • r = 3,窗口为 [1, 2, 3, 1]count = {1: 2, 2: 1, 3: 1}
    • 此时 1 的出现次数达到 2 次,贡献值为 7 - 3 = 4
  3. 左指针移动:

    • l = 1,窗口为 [2, 3, 1]count = {1: 1, 2: 1, 3: 1}
    • r = 4,窗口为 [2, 3, 1, 2]count = {1: 1, 2: 2, 3: 1}
    • 此时 2 的出现次数达到 2 次,贡献值为 7 - 4 = 3
  4. 继续移动:

    • 重复上述过程,直到右指针 r 到达数组末尾。

总结

  • 该代码通过滑动窗口的方法,高效地统计了数组中所有 k-优雅子数组的数量。
  • 使用双指针和 HashMap 记录窗口内各数字的出现次数,确保统计结果正确。
  • 每次找到符合要求的子数组后,计算贡献值并累加到结果中,避免了重复计算。

四、Python算法源码

以下是 Python 代码的详细注释和讲解,帮助理解每一部分的作用和逻辑:


代码讲解

# 输入获取
n, k = map(int, input().split())  # 读取数组长度 n 和优雅阈值 k
arr = list(map(int, input().split()))  # 读取数组元素并转换为整数列表

# 算法入口
def getResult(arr, n, k):
    # 初始化变量 ans,用于记录 k-优雅子数组的数量
    ans = 0

    # 初始化双指针 l 和 r,分别表示滑动窗口的左边界和右边界
    l = 0
    r = 0

    # 定义字典 count,用于记录滑动窗口内各数字的出现次数
    count = {}

    # 使用滑动窗口遍历数组
    while l < n and r < n:
        # 获取右指针 r 指向的数组元素
        c = arr[r]

        # 如果当前数字 c 不在 count 中,则初始化为 0
        if count.get(c) is None:
            count[c] = 0

        # 更新当前数字 c 的出现次数
        count[c] += 1

        # 如果当前数字 c 的出现次数达到 k 次
        if count[c] >= k:
            # 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求
            ans += n - r

            # 左指针 l 右移一格,减少左边界元素的计数
            count[arr[l]] -= 1
            l += 1

            # 右指针 r 左移一格,回退到上一个位置
            count[c] -= 1
            r -= 1

        # 右指针 r 右移一格,继续扩展窗口
        r += 1

    # 返回最终找到的 k-优雅子数组的数量
    return ans

# 算法调用
print(getResult(arr, n, k))

代码逻辑详解

  1. 输入处理:

    • 使用 input().split() 读取输入的两行数据。
    • 第一行数据解析为数组长度 n 和优雅阈值 k
    • 第二行数据解析为数组 arr,并将其转换为整数列表。
  2. 滑动窗口初始化:

    • 定义双指针 lr,分别表示滑动窗口的左边界和右边界,初始值均为 0。
    • 定义字典 count,用于记录滑动窗口内各数字的出现次数。
  3. 滑动窗口遍历:

    • 使用 while 循环遍历数组,右指针 r 从 0 开始逐步向右移动。
    • 对于每个右指针 r 指向的元素 c,更新其在 count 中的出现次数。
  4. 判断是否符合条件:

    • 如果当前数字 c 的出现次数达到 k 次,则:
      • 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求,贡献值为 n - r
      • 左指针 l 右移一格,减少左边界元素的计数。
      • 右指针 r 左移一格,回退到上一个位置。
  5. 右指针移动:

    • 右指针 r 右移一格,继续扩展窗口。
  6. 返回结果:

    • 遍历结束后,返回 ans,即 k-优雅子数组的数量。

示例运行

以输入 7 2 和数组 [1, 2, 3, 1, 2, 3, 1] 为例:

  1. 初始状态:

    • l = 0, r = 0
    • 窗口为 [1]count = {1: 1}
  2. 右指针移动:

    • r = 1,窗口为 [1, 2]count = {1: 1, 2: 1}
    • r = 2,窗口为 [1, 2, 3]count = {1: 1, 2: 1, 3: 1}
    • r = 3,窗口为 [1, 2, 3, 1]count = {1: 2, 2: 1, 3: 1}
    • 此时 1 的出现次数达到 2 次,贡献值为 7 - 3 = 4
  3. 左指针移动:

    • l = 1,窗口为 [2, 3, 1]count = {1: 1, 2: 1, 3: 1}
    • r = 4,窗口为 [2, 3, 1, 2]count = {1: 1, 2: 2, 3: 1}
    • 此时 2 的出现次数达到 2 次,贡献值为 7 - 4 = 3
  4. 继续移动:

    • 重复上述过程,直到右指针 r 到达数组末尾。

总结

  • 该代码通过滑动窗口的方法,高效地统计了数组中所有 k-优雅子数组的数量。
  • 使用双指针和字典记录窗口内各数字的出现次数,确保统计结果正确。
  • 每次找到符合要求的子数组后,计算贡献值并累加到结果中,避免了重复计算。

五、C/C++算法源码:

以下是 C++C语言 代码的中文详细注释和讲解,帮助理解每一部分的作用和逻辑:


C++ 代码

#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

int getResult(vector<int>& arr, int n, int k) {
    int ans = 0; // 用于记录 k-优雅子数组的数量

    int l = 0; // 滑动窗口的左边界
    int r = 0; // 滑动窗口的右边界
    unordered_map<int, int> count; // 用于记录滑动窗口内各数字的出现次数

    // 使用滑动窗口遍历数组
    while (l < n && r < n) {
        int c = arr[r]; // 获取右指针 r 指向的数组元素

        // 如果当前数字 c 不在 count 中,则初始化为 0
        if (count.find(c) == count.end()) {
            count[c] = 0;
        }

        // 更新当前数字 c 的出现次数
        count[c]++;

        // 如果当前数字 c 的出现次数达到 k 次
        if (count[c] >= k) {
            // 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求
            ans += n - r;

            // 左指针 l 右移一格,减少左边界元素的计数
            count[arr[l]]--;
            l++;

            // 右指针 r 左移一格,回退到上一个位置
            count[c]--;
            r--;
        }

        // 右指针 r 右移一格,继续扩展窗口
        r++;
    }

    // 返回最终找到的 k-优雅子数组的数量
    return ans;
}

int main() {
    int n, k;
    cin >> n >> k; // 读取数组长度 n 和优雅阈值 k

    vector<int> arr(n);
    for (int i = 0; i < n; i++) {
        cin >> arr[i]; // 读取数组元素
    }

    // 调用 getResult 函数,计算 k-优雅子数组的数量,并输出结果
    cout << getResult(arr, n, k) << endl;

    return 0;
}

C 语言代码

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 100000 // 定义数组的最大长度

int getResult(int arr[], int n, int k) {
    int ans = 0; // 用于记录 k-优雅子数组的数量

    int l = 0; // 滑动窗口的左边界
    int r = 0; // 滑动窗口的右边界
    int count[MAX_SIZE] = {0}; // 用于记录滑动窗口内各数字的出现次数

    // 使用滑动窗口遍历数组
    while (l < n && r < n) {
        int c = arr[r]; // 获取右指针 r 指向的数组元素

        // 更新当前数字 c 的出现次数
        count[c]++;

        // 如果当前数字 c 的出现次数达到 k 次
        if (count[c] >= k) {
            // 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求
            ans += n - r;

            // 左指针 l 右移一格,减少左边界元素的计数
            count[arr[l]]--;
            l++;

            // 右指针 r 左移一格,回退到上一个位置
            count[c]--;
            r--;
        }

        // 右指针 r 右移一格,继续扩展窗口
        r++;
    }

    // 返回最终找到的 k-优雅子数组的数量
    return ans;
}

int main() {
    int n, k;
    scanf("%d %d", &n, &k); // 读取数组长度 n 和优雅阈值 k

    int arr[MAX_SIZE];
    for (int i = 0; i < n; i++) {
        scanf("%d", &arr[i]); // 读取数组元素
    }

    // 调用 getResult 函数,计算 k-优雅子数组的数量,并输出结果
    printf("%d\n", getResult(arr, n, k));

    return 0;
}

代码逻辑详解

  1. 输入处理:

    • C++: 使用 cin 从控制台读取输入的数组长度 n 和优雅阈值 k,以及数组 arr
    • C: 使用 scanf 从控制台读取输入的数组长度 n 和优雅阈值 k,以及数组 arr
  2. 滑动窗口初始化:

    • 定义双指针 lr,分别表示滑动窗口的左边界和右边界,初始值均为 0。
    • 定义哈希表(C++ 使用 unordered_map,C 使用数组)count,用于记录滑动窗口内各数字的出现次数。
  3. 滑动窗口遍历:

    • 使用 while 循环遍历数组,右指针 r 从 0 开始逐步向右移动。
    • 对于每个右指针 r 指向的元素 c,更新其在 count 中的出现次数。
  4. 判断是否符合条件:

    • 如果当前数字 c 的出现次数达到 k 次,则:
      • 计算当前窗口的贡献值,即从当前右边界到数组末尾的所有子数组都符合要求,贡献值为 n - r
      • 左指针 l 右移一格,减少左边界元素的计数。
      • 右指针 r 左移一格,回退到上一个位置。
  5. 右指针移动:

    • 右指针 r 右移一格,继续扩展窗口。
  6. 返回结果:

    • 遍历结束后,返回 ans,即 k-优雅子数组的数量。

示例运行

以输入 7 2 和数组 [1, 2, 3, 1, 2, 3, 1] 为例:

  1. 初始状态:

    • l = 0, r = 0
    • 窗口为 [1]count = {1: 1}
  2. 右指针移动:

    • r = 1,窗口为 [1, 2]count = {1: 1, 2: 1}
    • r = 2,窗口为 [1, 2, 3]count = {1: 1, 2: 1, 3: 1}
    • r = 3,窗口为 [1, 2, 3, 1]count = {1: 2, 2: 1, 3: 1}
    • 此时 1 的出现次数达到 2 次,贡献值为 7 - 3 = 4
  3. 左指针移动:

    • l = 1,窗口为 [2, 3, 1]count = {1: 1, 2: 1, 3: 1}
    • r = 4,窗口为 [2, 3, 1, 2]count = {1: 1, 2: 2, 3: 1}
    • 此时 2 的出现次数达到 2 次,贡献值为 7 - 4 = 3
  4. 继续移动:

    • 重复上述过程,直到右指针 r 到达数组末尾。

总结

  • C++C 代码逻辑一致,均通过滑动窗口的方法高效地统计了数组中所有 k-优雅子数组的数量。
  • 使用双指针和哈希表(或数组)记录窗口内各数字的出现次数,确保统计结果正确。
  • 每次找到符合要求的子数组后,计算贡献值并累加到结果中,避免了重复计算。

六、尾言

什么是华为OD?

华为OD(Outsourcing Developer,外包开发工程师)是华为针对软件开发工程师岗位的一种招聘形式,主要包括笔试、技术面试以及综合面试等环节。尤其在笔试部分,算法题的机试至关重要。

为什么刷题很重要?

  1. 机试是进入技术面的第一关:
    华为OD机试(常被称为机考)主要考察算法和编程能力。只有通过机试,才能进入后续的技术面试环节。

  2. 技术面试需要手撕代码:
    技术一面和二面通常会涉及现场编写代码或算法题。面试官会注重考察候选人的思路清晰度、代码规范性以及解决问题的能力。因此提前刷题、多练习是通过面试的重要保障。

  3. 入职后的可信考试:
    入职华为后,还需要通过“可信考试”。可信考试分为三个等级:

    • 入门级:主要考察基础算法与编程能力。
    • 工作级:更贴近实际业务需求,可能涉及复杂的算法或与工作内容相关的场景题目。
    • 专业级:最高等级,考察深层次的算法以及优化能力,与薪资直接挂钩。

刷题策略与说明:

2024年8月14日之后,华为OD机试的题库转为 E卷,由往年题库(D卷、A卷、B卷、C卷)和全新题目组成。刷题时可以参考以下策略:

  1. 关注历年真题:

    • 题库中的旧题占比较大,建议优先刷历年的A卷、B卷、C卷、D卷题目。
    • 对于每道题目,建议深度理解其解题思路、代码实现,以及相关算法的适用场景。
  2. 适应新题目:

    • E卷中包含全新题目,需要掌握全面的算法知识和一定的灵活应对能力。
    • 建议关注新的刷题平台或交流群,获取最新题目的解析和动态。
  3. 掌握常见算法:
    华为OD考试通常涉及以下算法和数据结构:

    • 排序算法(快速排序、归并排序等)
    • 动态规划(背包问题、最长公共子序列等)
    • 贪心算法
    • 栈、队列、链表的操作
    • 图论(最短路径、最小生成树等)
    • 滑动窗口、双指针算法
  4. 保持编程规范:

    • 注重代码的可读性和注释的清晰度。
    • 熟练使用常见编程语言,如C++、Java、Python等。

如何获取资源?

  1. 官方参考:

    • 华为招聘官网或相关的招聘平台会有一些参考信息。
    • 华为OD的相关公众号可能也会发布相关的刷题资料或学习资源。
  2. 加入刷题社区:

    • 找到可信的刷题交流群,与其他备考的小伙伴交流经验。
    • 关注知名的刷题网站,如LeetCode、牛客网等,这些平台上有许多华为OD的历年真题和解析。
  3. 寻找系统性的教程:

    • 学习一本经典的算法书籍,例如《算法导论》《剑指Offer》《编程之美》等。
    • 完成系统的学习课程,例如数据结构与算法的在线课程。

积极心态与持续努力:

刷题的过程可能会比较枯燥,但它能够显著提升编程能力和算法思维。无论是为了通过华为OD的招聘考试,还是为了未来的职业发展,这些积累都会成为重要的财富。

考试注意细节

  1. 本地编写代码

    • 在本地 IDE(如 VS Code、PyCharm 等)上编写、保存和调试代码,确保逻辑正确后再复制粘贴到考试页面。这样可以减少语法错误,提高代码准确性。
  2. 调整心态,保持冷静

    • 遇到提示不足或实现不确定的问题时,不必慌张,可以采用更简单或更有把握的方法替代,确保思路清晰。
  3. 输入输出完整性

    • 注意训练和考试时都需要编写完整的输入输出代码,尤其是和题目示例保持一致。完成代码后务必及时调试,确保功能符合要求。
  4. 快捷键使用

    • 删除行可用 Ctrl+D,复制、粘贴和撤销分别为 Ctrl+CCtrl+VCtrl+Z,这些可以正常使用。
    • 避免使用 Ctrl+S,以免触发浏览器的保存功能。
  5. 浏览器要求

    • 使用最新版的 Google Chrome 浏览器完成考试,确保摄像头开启并正常工作。考试期间不要切换到其他网站,以免影响考试成绩。
  6. 交卷相关

    • 答题前,务必仔细查看题目示例,避免遗漏要求。
    • 每完成一道题后,点击【保存并调试】按钮,多次保存和调试是允许的,系统会记录得分最高的一次结果。完成所有题目后,点击【提交本题型】按钮。
    • 确保在考试结束前提交试卷,避免因未保存或调试失误而丢分。
  7. 时间和分数安排

    • 总时间:150 分钟;总分:400 分。
    • 试卷结构:2 道一星难度题(每题 100 分),1 道二星难度题(200 分)。及格分为 150 分。合理分配时间,优先完成自己擅长的题目。
  8. 考试环境准备

    • 考试前请备好草稿纸和笔。考试中尽量避免离开座位,确保监控画面正常。
    • 如需上厕所,请提前规划好时间以减少中途离开监控的可能性。
  9. 技术问题处理

    • 如果考试中遇到断电、断网、死机等技术问题,可以关闭浏览器并重新打开试卷链接继续作答。
    • 出现其他问题,请第一时间联系 HR 或监考人员进行反馈。

祝你考试顺利,取得理想成绩!


http://www.kler.cn/a/516306.html

相关文章:

  • C语言数组详解:从基础到进阶的全面解析
  • Vue基础(2)
  • python 找出合并并排序两个有序列表后的第n个最小元素
  • Effective Python系列(1.1):区别bytes和str
  • OpenCV:高通滤波之索贝尔、沙尔和拉普拉斯
  • 前端开发中的模拟后端与MVVM架构实践[特殊字符][特殊字符][特殊字符]
  • Javascript IndexedDB(Dexie.js) React 存储大量(5-50M)的完整示例
  • 规模化指令微调的语言模型
  • 谷歌(Google) Pixel 8/9 Pro(xl)如何获取 root 权限
  • 23. C语言 文件操作详解
  • GS-SLAM论文阅读--SplatMAP
  • SpringBoot使用MockMVC通过http请求controller控制器调用测试
  • leetcode_链表 21.合并两个有序链表
  • Github 2025-01-23 Go开源项目日报 Top10
  • 【29】Word:李楠-学术期刊❗
  • GPSd定时检测保活TCP GPS源
  • React 路由导航与传参详解
  • 力扣hot100-->滑动窗口、贪心
  • Vue入门(Vue基本语法、axios、组件、事件分发)
  • Python自带模块实现屏幕像素高效操作
  • VUE对接deepseekAPI调用
  • 【LeetCode 刷题】二叉树-深度优先遍历
  • Chromium 132 编译指南 Mac 篇(二)- 安装 Xcode
  • WPF-系统资源
  • 豆包MarsCode:小C点菜问题
  • 左/右侧边栏布局(Semi design)