实用指南:华为 ai 机考 编程题解答

写在前面

这道题目好像是 2025年9月12日参加华为ai岗位的机试考试的一道题目。题目网上有原题,也有类似的解答,我这里主要是讲一讲我对这道题目的想法,以及通过 C + + C++ C++ 编写的代码。(网上的都是 P y t h o n Python Python 写的代码),本人还是习惯使用 C + + C++ C++ 编写。

题目

b站上有个视频,专门讲解了这道题目的思路:华为9月12日AI岗考试题讲解-二叉树中序遍历的第k个祖先节点|BFS建树,中序遍历,模拟

题目的大致意思是(具体详见:二叉树中序遍历的第k个祖先节点):
在这里插入图片描述
在这里插入图片描述

我的思路

我的思路就是:

  • 首先对输入的数据节点进行建树,这里就需要构建一个结构体 construct TreeNode ,然后建立二叉树,同时子节点有个 fa 指针,指向父节点,便于后续操作。
  • 接着对二叉树进行中序遍历,并将结果存入到一个 inorderResult 数组中。
  • 接着在 inorderResult 数组中找到需要找寻的节点 node 的位置,然后标记其所有的父节点的 isAncestor = 1,表示是该节点的祖先节点
  • 最后从该位置向前遍历,每找到一个 isAncestor = 1 的节点,则 k–,直到 k==0,返回该位置的节点值。要是遍历到第一个元素 k 依旧不为 0 的话,返回 -1 即可。

于是我根据上述思路,编写的代码如下:

#include <iostream>
  #include <vector>
    #include <queue>
      #include <sstream>
        #include <string>
          using namespace std;
          struct TreeNode
          {
          int val;
          int isAncestor = 0;
          TreeNode *left;
          TreeNode *right;
          TreeNode *fa;
          // 用来找寻父节点
          TreeNode(int x) : val(x), left(nullptr), right(nullptr), fa(nullptr) {
          }
          };
          // 从输入字符串构建二叉树(层次遍历输入,# 表示 null)
          TreeNode *buildTree(const vector<string>
            &parts)
            {
            if (parts.empty() || parts[0] == "#")
            return nullptr;
            TreeNode *root = new TreeNode(stoi(parts[0]));
            root->fa = nullptr;
            queue<TreeNode *> q;
              // 引入一个队列,方便建树
              q.push(root);
              size_t i = 1;
              while (!q.empty() && i < parts.size())
              {
              TreeNode *node = q.front();
              q.pop();
              // 左子节点
              if (i < parts.size() && parts[i] != "#")
              {
              node->left = new TreeNode(stoi(parts[i]));
              node->left->fa = node;
              // 标记其父节点
              q.push(node->left);
              }
              else
              node->left = nullptr;
              // 表示 parts[i] == "#" ,此时其左子节点为空
              i++;
              // 右子节点
              if (i < parts.size() && parts[i] != "#")
              {
              node->right = new TreeNode(stoi(parts[i]));
              node->right->fa = node;
              q.push(node->right);
              }
              else
              node->right = nullptr;
              i++;
              }
              return root;
              }
              // 中序遍历,将节点值存入 result
              void inorder(TreeNode *root, vector<TreeNode *>
                &result)
                {
                if (root == nullptr)
                return;
                inorder(root->left, result);
                result.push_back(root);
                inorder(root->right, result);
                }
                int main()
                {
                string line;
                getline(cin, line);
                // 读取整行输入
                int node, k;
                cin >> node >> k;
                // 读取 node , k
                // 去除首尾空格
                // size_t start = line.find_first_not_of(" \t");
                // size_t end = line.find_last_not_of(" \t");
                // if (start == string::npos)
                // {
                // cout << -1 << endl;
                // return 0;
                // }
                // line = line.substr(start, end - start + 1);
                // 按空格分割字符串
                vector<string> parts;
                  stringstream ss(line);
                  string token;
                  while (ss >> token)
                  parts.push_back(token);
                  // 构建树
                  TreeNode *root = buildTree(parts);
                  // 中序遍历
                  vector<TreeNode *> inorderResult;
                    inorder(root, inorderResult);
                    // 找到目标节点在中序遍历中的位置
                    int len = inorderResult.size();
                    int temp = 0;
                    for (; temp < len; temp++)
                    if (inorderResult[temp]->val == node)
                    break;
                    // 目标节点的祖先节点的 isAncestor 为 1
                    TreeNode *current = inorderResult[temp];
                    while (current->fa != nullptr)
                    {
                    current->fa->isAncestor = 1;
                    current = current->fa;
                    }
                    // 查询第 k 个祖先节点
                    for (int i = temp - 1; i >= 0; i--)
                    {
                    if (inorderResult[i]->isAncestor == 1)
                    k--;
                    if (k == 0)
                    {
                    cout << inorderResult[i]->val << endl;
                      // 重置 isAncestor 标记
                      for (TreeNode *node : inorderResult)
                      node->isAncestor = 0;
                      return 0;
                      }
                      }
                      // 重置 isAncestor 标记
                      for (TreeNode *node : inorderResult)
                      node->isAncestor = 0;
                      // 遍历完 k 都不为 0 ,输出 -1 即可。
                      cout <<
                      -1 << endl;
                      return 0;
                      }

我参加的一次

非常荣幸,我参加了2025年9月17号华为 ai 的机考,题目感觉出的不是很难,都是我复习到的,于是考试结果也还不错。
详细题目参见:CodeFun 2000

选择题就不做说明了,主要讲解一下编程题吧:

题目一(300分):大模型分词

题目详见:大模型分词

刚好我力扣刷到了 hot100 的动态规划专题,因此一看这道题目就是使用动态规划进行求解,只是需要对输入进行预处理即可,于是可以选择使用 C++ 中的 unordered_map 进行映射存储。

// we have defined the necessary header files here for this problem.
// If additional header files are needed in your program, please import here.
#include <iostream>
  #include <vector>
    #include <string>
      #include <unordered_map>
        #include <climits>
          // #include<bits/stdc++.h>
            using namespace std;
            int maxScore(const string &text, const unordered_map<string, int>
              &confidence, const unordered_map<string, int>
                &transfer)
                {
                int n = text.length();
                vector<
                int>
                dp(n + 1, INT_MIN);
                dp[0] = 0;
                // 每个位置记录一下最优的前驱
                vector<
                int>
                prev(n + 1, -1);
                for (int i = 1; i <= n; i++)
                {
                for (int j = 0; j < i; j++)
                {
                string word = text.substr(j, i - j);
                if (confidence.find(word) != confidence.end())
                {
                int word_score = confidence.at(word);
                int transition_score = 0;
                // 不是第一个词的话,检查转移分数?
                if (j >
                0 && prev[j] != -1)
                {
                string prev_word = text.substr(prev[j], j - prev[j]);
                string transition_key = prev_word + " " + word;
                if (transfer.find(transition_key) != transfer.end())
                {
                transition_score = transfer.at(transition_key);
                }
                }
                int total_score = dp[j] + word_score + transition_score;
                if (total_score > dp[i])
                {
                dp[i] = total_score;
                prev[i] = j;
                // 更新前驱位置
                }
                }
                }
                }
                return dp[n] == INT_MIN ? 0 : dp[n];
                }
                int main()
                {
                // please define the C++ input here. For example: int a,b; cin>>a>>b;;
                // please finish the function body here.
                // please define the C++ output here. For example:cout<<____<<endl;
                // 读入英文单词
                string text;
                // 读入 n 和 m
                int n, m;
                cin >> text;
                cin >> n;
                unordered_map<string, int> confidence;
                  // 已标注词元和置信度分数P,使用哈希进行存储
                  for (int i = 0; i < n; i++)
                  {
                  string word;
                  int score;
                  cin >> word >> score;
                  confidence[word] = score;
                  }
                  cin >> m;
                  // 转移分数数据:起始词、下一个词、转移分数加分X、空格分隔
                  unordered_map<string, int> transfer;
                    for (int i = 0; i < m; i++)
                    {
                    string prevWord, nextWord;
                    int score;
                    cin >> prevWord >> nextWord >> score;
                    transfer[prevWord + " " + nextWord] = score;
                    }
                    int result = maxScore(text, confidence, transfer);
                    cout << result << endl;
                    return 0;
                    }

但是这段代码在华为的评判系统的只过了 90% 的测试用例,还有 10% 没有通过,因此不知道主要问题在哪里,读者若有发现,麻烦详细解答一下,笔者在此不胜感激。

题目二(150分):大模型Attention模块开发

题目详见:大模型Attention模块开发

感觉要是知道点 T r a n s f o r m e r Transformer Transformer 的都应该知道这个 A t t e n t i o n Attention Attention 模块,因此这道题目还是比较好写的:

# If you need to import additional packages or classes, please import here.
import numpy as np
def attention_module(n, m, h):
# 构建全 1 的矩阵
X = np.ones((n, m))
# 构建上三角矩阵
W1 = np.triu(np.ones((m, h)))
W2 = np.triu(np.ones((m, h)))
W3 = np.triu(np.ones((m, h)))
# 计算 Q K V
Q = np.dot(X, W1)
K = np.dot(X, W2)
V = np.dot(X, W3)
# 计算
QK_T = np.dot(Q, K.T)/np.sqrt(h)
# 计算 softmax(QK_T)
M = np.exp(QK_T)
softmax_QK_T = M / np.sum(M, axis=1, keepdims=True)
Y = np.dot(softmax_QK_T, V)
return int(np.round(np.sum(Y)))
def func():
# please define the python3 input here. For example: a,b = map(int, input().strip().split())
# please finish the function body here.
# please define the python3 output here. For example: print().
# 读入输入
n, m, h = map(int, input().strip().split())
print(attention_module(n, m, h))
if __name__ == "__main__":
func()
posted @ 2025-09-22 10:49  yxysuanfa  阅读(83)  评论(0)    收藏  举报