华为OD机试 2024E卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
Excel工作表中对选定区域的数值进行统计的功能非常实用。仿照Excel的这个功能,请你给定表格中区域中的单元格进行求和统计,并输出统计结果。
为简化计算,假设当前输入中每个单元格内容仅为数字或公式两种。
如果为数字,则是一个非负整数,形如3,77。
如果为公式,则固定以“=”开头,且包含以下三种情况:
- 等于某单元格的值,例如=B12;
- 两个单元格的双目运算(仅为+或-),形如=C1-C2,C3+B2;
- 单元格和数字的双目运算(仅为+或-),形如=B1+1,100-B2。
注意:
公式内容都是合法的,例如不存在=,=C+1,=C1-C2+B3=5,=3+5;
不存在循环引用,例如A1=B1+C1,C1=A1+B2;
内容中不存在空格、括号。
二、输入描述
第一行两个整数rows、cols,表示给定表格区域的行数和列数,1<=rows<=20,1<=cols<=26。
接下来rows行,每行cols个以空格分隔的字符串values,表示表格values的单元格内容。
最后一行给出一个字符串,表示给定的统计区域,形如A1
三、输出描述
一个整数,表示给定选定区域中单元格数字的累加总和,范围为-2,147,483,648 ~ 2,147,483,647。
四、测试用例
1、输入
1 3
1 =A1+C1 3
A1:C1
2、输出
8
3、说明
A1 = 1
B1 = A1 + C1 = 1 + 3 = 4
C1 = 3
总和 = 1 + 4 + 3 = 8
五、解题思路
题目要求对Excel工作表中选定区域的单元格进行求和统计。每个单元格的内容可能是一个数字或一个公式。
具体步骤
- 输入处理:
- 读取表格的行数和列数。
- 读取每个单元格的内容,并存储在一个二维数组中。
- 读取需要统计的区域范围。
- 区域解析:
- 解析统计区域的起始和结束单元格,例如“A1
- ”表示从A1到C1的所有单元格。
- 将单元格的字母部分(列)转换为数字索引,数字部分(行)转换为数组索引。
- 单元格值计算:
- 对于每个单元格,如果是数字,直接取其值。
- 如果是公式,需要解析公式并计算其结果。公式可能涉及其他单元格的值或直接的数值运算。
- 使用递归或记忆化递归来处理公式中引用的单元格,避免重复计算。
- 求和:
- 遍历选定区域内的所有单元格,计算每个单元格的值并累加。
- 输出结果。
六、Python算法源码
import sys
# 定义全局变量
table = [] # 存储表格内容的二维列表
memo = {} # 记忆化存储已计算的单元格值
rows = 0 # 表格的行数
cols = 0 # 表格的列数
def cell_to_index(cell):
"""
将单元格标识转换为行列索引
例如:'A1' -> (0, 0)
"""
col = 0
i = 0
# 处理列(字母部分)
while i < len(cell) and cell[i].isalpha():
col = col * 26 + (ord(cell[i].upper()) - ord('A') + 1)
i += 1
# 处理行(数字部分)
row = int(cell[i:]) - 1
return (row, col - 1)
def index_to_cell(row, col):
"""
将行列索引转换为单元格标识
例如:(0, 0) -> 'A1'
"""
cell = ""
col += 1
while col > 0:
rem = (col - 1) % 26
cell = chr(ord('A') + rem) + cell
col = (col - 1) // 26
cell += str(row + 1)
return cell
def evaluate(row, col):
"""
计算指定单元格的值
"""
cell = index_to_cell(row, col)
# 如果已经计算过,直接返回记忆化的值
if cell in memo:
return memo[cell]
content = table[row][col]
if not content.startswith('='):
# 如果是数字,直接转换为整数
value = int(content)
else:
# 如果是公式,解析并计算表达式
expr = content[1:] # 去掉 '='
value = evaluate_expression(expr)
# 记忆化存储计算结果
memo[cell] = value
return value
def evaluate_expression(expr):
"""
解析并计算表达式
支持单个操作符 '+' 或 '-'
"""
# 查找运算符的位置
op_pos = -1
op = ''
for i, char in enumerate(expr):
if char in ['+', '-']:
op_pos = i
op = char
break
if op_pos == -1:
# 没有运算符,可能是单元格引用或数字
return parse_term(expr)
else:
# 分割表达式为左半部分和右半部分
left = expr[:op_pos]
right = expr[op_pos+1:]
left_val = parse_term(left)
right_val = parse_term(right)
if op == '+':
return left_val + right_val
else:
return left_val - right_val
def parse_term(term):
"""
解析单个项,可能是单元格引用或数字
"""
if term[0].isalpha():
# 如果是单元格引用,递归计算其值
row, col = cell_to_index(term)
return evaluate(row, col)
else:
# 如果是数字,直接转换为整数
return int(term)
def main():
global rows, cols, table
# 读取输入
input = sys.stdin.read().splitlines()
# 第一行:行数和列数
rows, cols = map(int, input[0].split())
# 读取表格内容
table = []
for i in range(1, rows + 1):
table.append(input[i].split())
# 读取统计区域
range_str = input[rows + 1]
cells = range_str.split(':')
start = cell_to_index(cells[0])
end = cell_to_index(cells[1])
# 计算总和
total = 0
for r in range(start[0], end[0] + 1):
for c in range(start[1], end[1] + 1):
total += evaluate(r, c)
# 输出结果
print(total)
if __name__ == "__main__":
main()
七、JavaScript算法源码
const readline = require('readline');
// 创建接口以读取输入
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let input = [];
rl.on('line', function(line){
input.push(line);
}).on('close', function(){
// 开始处理输入
let index = 0;
// 读取行数和列数
let [rows, cols] = input[index++].split(' ').map(Number);
// 读取表格内容
let table = [];
for(let i=0; i<rows; i++){
table.push(input[index++].split(' '));
}
// 读取统计区域
let range = input[index++].trim();
let cells = range.split(':');
let start = cellToIndex(cells[0]);
let end = cellToIndex(cells[1]);
// 初始化记忆化存储
let memo = new Map();
// 计算总和
let total = 0;
for(let r = start.row; r <= end.row; r++){
for(let c = start.col; c <= end.col; c++){
total += evaluate(r, c);
}
}
// 输出结果
console.log(total);
// 函数定义
function cellToIndex(cell){
let col = 0;
let i = 0;
while(i < cell.length && /[A-Z]/.test(cell[i])){
col = col * 26 + (cell.charCodeAt(i) - 'A'.charCodeAt(0) + 1);
i++;
}
let row = parseInt(cell.substring(i)) - 1;
return {row: row, col: col - 1};
}
function indexToCell(row, col){
let cell = "";
col +=1;
while(col >0){
let rem = (col -1) %26;
cell = String.fromCharCode('A'.charCodeAt(0) + rem) + cell;
col = Math.floor((col -1)/26);
}
cell += (row +1).toString();
return cell;
}
function evaluate(row, col){
let cell = indexToCell(row, col);
if(memo.has(cell)){
return memo.get(cell);
}
let content = table[row][col];
let value = 0;
if(!content.startsWith('=')){
value = parseInt(content);
}
else{
let expr = content.substring(1);
value = evaluateExpression(expr);
}
memo.set(cell, value);
return value;
}
function evaluateExpression(expr){
let opPos = -1;
let op = '';
for(let i=0; i<expr.length; i++){
if(expr[i] === '+' || expr[i] === '-'){
opPos = i;
op = expr[i];
break;
}
}
if(opPos === -1){
return parseTerm(expr);
}
else{
let left = expr.substring(0, opPos);
let right = expr.substring(opPos+1);
let leftVal = parseTerm(left);
let rightVal = parseTerm(right);
return op === '+' ? leftVal + rightVal : leftVal - rightVal;
}
}
function parseTerm(term){
if(/[A-Z]/.test(term[0])){
let idx = cellToIndex(term);
return evaluate(idx.row, idx.col);
}
else{
return parseInt(term);
}
}
});
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_ROWS 20
#define MAX_COLS 26
#define MAX_CELL_LEN 100
#define MAX_EXPR_LEN 1000
// 定义表格内容
char table[MAX_ROWS][MAX_COLS][MAX_CELL_LEN];
// 记忆化存储单元格值,初始化为未计算状态
long long memo_val[MAX_ROWS][MAX_COLS];
int memo_flag[MAX_ROWS][MAX_COLS] = {0};
// 表格的行数和列数
int rows, cols;
// 将单元格标识转换为行列索引
void cell_to_index(char *cell, int *row, int *col){
*col = 0;
int i = 0;
// 处理列(字母部分)
while(cell[i] && isalpha(cell[i])){
*col = (*col) * 26 + (toupper(cell[i]) - 'A' + 1);
i++;
}
// 处理行(数字部分)
char num_part[MAX_CELL_LEN];
int j = 0;
while(cell[i]){
num_part[j++] = cell[i++];
}
num_part[j] = '\0';
*row = atoi(num_part) -1;
*col = *col -1;
}
// 将行列索引转换为单元格标识
void index_to_cell(int row, int col, char *cell){
cell[0] = '\0';
col +=1;
char temp[10];
while(col >0){
int rem = (col -1) %26;
char c = 'A' + rem;
sprintf(temp, "%c", c);
strcat(cell, temp);
col = (col -1) /26;
}
char row_str[10];
sprintf(row_str, "%d", row +1);
strcat(cell, row_str);
}
// 解析并计算表达式
long long evaluate_expression(char *expr);
// 解析单个项,可能是单元格引用或数字
long long parse_term(char *term){
if(isalpha(term[0])){
int r, c;
cell_to_index(term, &r, &c);
return evaluate(r, c);
}
else{
return atoll(term);
}
}
// 计算单元格的值
long long evaluate(int row, int col){
// 如果已经计算过,直接返回
if(memo_flag[row][col]){
return memo_val[row][col];
}
char *content = table[row][col];
long long value =0;
if(content[0] != '='){
// 直接是数字
value = atoll(content);
}
else{
// 是公式,解析并计算表达式
char expr[MAX_EXPR_LEN];
strcpy(expr, content +1); // 去掉 '='
value = evaluate_expression(expr);
}
// 记忆化存储
memo_val[row][col] = value;
memo_flag[row][col] =1;
return value;
}
// 解析并计算表达式
long long evaluate_expression(char *expr){
int op_pos = -1;
char op = 0;
// 查找运算符的位置
for(int i=0; i<strlen(expr); i++){
if(expr[i] == '+' || expr[i] == '-'){
op_pos = i;
op = expr[i];
break;
}
}
if(op_pos == -1){
// 没有运算符,可能是单元格引用或数字
char term[MAX_CELL_LEN];
strcpy(term, expr);
return parse_term(term);
}
else{
// 分割表达式为左半部分和右半部分
char left[MAX_CELL_LEN];
strncpy(left, expr, op_pos);
left[op_pos] = '\0';
char right[MAX_CELL_LEN];
strcpy(right, expr + op_pos +1);
long long left_val = parse_term(left);
long long right_val = parse_term(right);
if(op == '+'){
return left_val + right_val;
}
else{
return left_val - right_val;
}
}
}
int main(){
// 读取行数和列数
scanf("%d %d", &rows, &cols);
// 读取表格内容
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
scanf("%s", table[i][j]);
}
}
// 读取统计区域
char range[20];
scanf("%s", range);
// 解析统计区域的起始和结束单元格
char *token = strtok(range, ":");
char start_cell[MAX_CELL_LEN];
char end_cell[MAX_CELL_LEN];
strcpy(start_cell, token);
token = strtok(NULL, ":");
strcpy(end_cell, token);
int start_r, start_c, end_r, end_c;
cell_to_index(start_cell, &start_r, &start_c);
cell_to_index(end_cell, &end_r, &end_c);
// 计算总和
long long total =0;
for(int r=start_r; r<=end_r; r++){
for(int c=start_c; c<=end_c; c++){
total += evaluate(r, c);
}
}
// 输出结果
printf("%lld\n", total);
return 0;
}
九、C++算法源码
#include <bits/stdc++.h>
using namespace std;
// 定义表格内容
vector<vector<string>> table;
// 记忆化存储单元格值
long long memo_val[21][27];
bool memo_flag[21][27];
// 表格的行数和列数
int rows, cols;
// 将单元格标识转换为行列索引
pair<int, int> cell_to_index(string cell){
int col =0;
int i=0;
// 处理列(字母部分)
while(i < cell.size() && isalpha(cell[i])){
col = col *26 + (toupper(cell[i]) - 'A' +1);
i++;
}
// 处理行(数字部分)
int row = stoi(cell.substr(i)) -1;
return {row, col -1};
}
// 将行列索引转换为单元格标识
string index_to_cell(int row, int col){
string cell = "";
col +=1;
while(col >0){
int rem = (col -1) %26;
cell = char('A' + rem) + cell;
col = (col -1)/26;
}
cell += to_string(row +1);
return cell;
}
// 解析并计算表达式
long long evaluate_expression(string expr);
// 解析单个项,可能是单元格引用或数字
long long parse_term(string term){
if(isalpha(term[0])){
pair<int, int> idx = cell_to_index(term);
return evaluate(idx.first, idx.second);
}
else{
return stoll(term);
}
}
// 计算单元格的值
long long evaluate(int row, int col){
// 如果已经计算过,直接返回
if(memo_flag[row][col]){
return memo_val[row][col];
}
string content = table[row][col];
long long value =0;
if(content[0] != '='){
// 直接是数字
value = stoll(content);
}
else{
// 是公式,解析并计算表达式
string expr = content.substr(1); // 去掉 '='
value = evaluate_expression(expr);
}
// 记忆化存储
memo_val[row][col] = value;
memo_flag[row][col] = true;
return value;
}
// 解析并计算表达式
long long evaluate_expression(string expr){
int op_pos = -1;
char op = 0;
// 查找运算符的位置
for(int i=0; i<expr.size(); i++){
if(expr[i] == '+' || expr[i] == '-'){
op_pos = i;
op = expr[i];
break;
}
}
if(op_pos == -1){
// 没有运算符,可能是单元格引用或数字
return parse_term(expr);
}
else{
// 分割表达式为左半部分和右半部分
string left = expr.substr(0, op_pos);
string right = expr.substr(op_pos +1);
long long left_val = parse_term(left);
long long right_val = parse_term(right);
if(op == '+'){
return left_val + right_val;
}
else{
return left_val - right_val;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
// 读取行数和列数
cin >> rows >> cols;
// 读取表格内容
table.assign(rows, vector<string>(cols));
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
cin >> table[i][j];
memo_flag[i][j] = false;
}
}
// 读取统计区域
string range;
cin >> range;
// 解析统计区域的起始和结束单元格
size_t pos = range.find(':');
string start_cell = range.substr(0, pos);
string end_cell = range.substr(pos +1);
pair<int, int> start = cell_to_index(start_cell);
pair<int, int> end = cell_to_index(end_cell);
// 计算总和
long long total =0;
for(int r = start.first; r <= end.first; r++){
for(int c = start.second; c <= end.second; c++){
total += evaluate(r, c);
}
}
// 输出结果
cout << total << "\n";
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。