【OD机试题笔记】火星文计算

题目描述

已知火星人使用的运算符为#、$,其与地球人的等价公式如下:

x#y = 2x+3y+4

x$y = 3*x+y+2

其中x、y是无符号整数
地球人公式按C语言规则计算
火星人公式中,$的优先级高于#,相同的运算符,按从左到右的顺序计算
现有一段火星人的字符串报文,请你来翻译并计算结果。

输入描述
火星人字符串表达式(结尾不带回车换行)

输入的字符串说明:字符串为仅由无符号整数和操作符(#、$)组成的计算表达式。

例如:123#4$5#67$78。

用例保证字符串中,操作数与操作符之间没有任何分隔符。
用例保证操作数取值范围为32位无符号整数。
保证输入以及计算结果不会出现整型溢出。
保证输入的字符串为合法的求值报文,例如:123#4$5#67$78
保证不会出现非法的求值报文,例如类似这样字符串:
#4$5 //缺少操作数

4$5# //缺少操作数

4#$5 //缺少操作数

4 $5 //有空格

3+4-5*6/7 //有其它操作符

12345678987654321$54321 //32位整数计算溢出

输出描述
根据输入的火星人字符串输出计算结果(结尾不带回车换行)。

用例
输入 7#6$5#12
输出 226
说明
7#6$5#12

=7#(3*6+5+2)#12

=7#25#12

=(27+325+4)#12

=93#12

=293+312+4

=226

思路

1. 双栈法(数组模拟栈)

  • 核心步骤
    1. 拆分表达式为数字数组(nums)和运算符数组(ops);
    2. 高优先级优先:遍历ops,遇$则取出nums中对应两个数计算(3x+y+2),替换nums并删除该$,重复至无$
    3. 低优先级处理:遍历剩余ops,遇#则取出nums中对应两个数计算(2x+3y+4),替换nums并删除该#
    4. 最终nums中唯一元素即为结果。
  • 核心逻辑:通过数组模拟栈结构,按优先级分批次修改数组,逐步合并计算结果。
  • 时空复杂度:时间复杂度O(n)(n为表达式长度),空间复杂度O(n)。

2. 正则表达式替换法

  • 核心步骤
    1. 高优先级处理:用正则匹配数字$数字格式子串,计算结果后替换原串,循环至无$
    2. 低优先级处理:将剩余字符串按#分割为数字数组,从左到右依次计算#运算;
    3. 输出最终累加结果。
  • 核心逻辑:利用正则精准匹配高优先级运算子串,替换后简化表达式,再处理低优先级运算。
  • 时空复杂度:时间复杂度O(n²)(最坏情况)/ O(n)(最好情况),空间复杂度O(n)(n为表达式长度)。

3. 调度场算法(线性扫描+分步求值)

  • 核心步骤
    1. 分词:将表达式拆分为数字、运算符的token列表;
    2. 高优先级求值:遍历token,遇$则弹出前一个数字与后一个数字计算,结果入临时数组,跳过已计算的数字;
    3. 低优先级求值:遍历临时数组,从左到右依次计算所有#运算;
    4. 输出最终结果。
  • 核心逻辑:线性扫描token流,优先处理高优先级运算符,将结果融入临时数组,再顺序处理低优先级运算符。
  • 时空复杂度:时间复杂度O(n)(n为表达式长度),空间复杂度O(n)。

代码

// 双栈法
function solution() {
    const s = readline();
    // 步骤1:解析字符串为数字数组和运算符数组
    const nums = [];
    const ops = [];
    let numStr = '';
    
    for (const c of s) {
        if (c === '#' || c === '$') {
            // 遇到运算符,将之前的数字入栈
            nums.push(Number(numStr));
            numStr = '';
            ops.push(c);
        } else {
            // 拼接数字字符串
            numStr += c;
        }
    }
    // 最后一个数字入栈
    nums.push(Number(numStr));
    
    // 步骤2:先处理所有$运算符(优先级高)
    let i = 0;
    while (i < ops.length) {
        if (ops[i] === '$') {
            // 计算x$y = 3x + y + 2
            const x = nums[i];
            const y = nums[i + 1];
            nums.splice(i, 2, 3 * x + y + 2); // 替换为结果
            ops.splice(i, 1); // 移除当前$
            // 索引不变,继续检查当前位置(可能有连续$)
        } else {
            i++; // 不是$,继续下一个
        }
    }
    
    // 步骤3:处理剩余的#运算符(优先级低)
    i = 0;
    while (i < ops.length) {
        if (ops[i] === '#') {
            // 计算x#y = 2x + 3y + 4
            const x = nums[i];
            const y = nums[i + 1];
            nums.splice(i, 2, 2 * x + 3 * y + 4); // 替换为结果
            ops.splice(i, 1); // 移除当前#
            // 索引不变,继续检查当前位置
        } else {
            i++;
        }
    }
    
    // 最终结果为nums中唯一的元素
    console.log(nums[0]);
}

// 正则表达式
function solution2() {
    let s = readline();
    // 匹配形如"数字$数字"的正则表达式
    const pattern = /(\d+)\$(\d+)/;
    // 循环替换所有符合规则的子串,直到没有匹配
    while (pattern.test(s)) {
        const match = pattern.exec(s);
        const x = parseInt(match[1], 10);
        const y = parseInt(match[2], 10);
        // 替换第一个匹配项为3x + y + 2的结果
        s = s.replace(pattern, 3 * x + y + 2);
    }
    // 按"#"分割并转换为数字数组
    const arr = s.split('#').map(Number);
    // 计算最终结果
    let x = arr[0];
    for (const y of arr.slice(1)) {
        x = 2 * x + 3 * y + 4;
    }
    console.log(x);
}

// 调度场算法
function solution3() {
    const s = readline().trim();
    
    // Step 1: Tokenize
    const tokens = [];
    let num = '';
    for (let c of s) {
        if (c === '#' || c === '$') {
            tokens.push(Number(num));
            tokens.push(c);
            num = '';
        } else {
            num += c;
        }
    }
    tokens.push(Number(num)); // last number

    // Step 2: Evaluate all $ first (higher precedence)
    const afterDollar = [];
    for (let i = 0; i < tokens.length; i++) {
        if (tokens[i] === '$') {
            const x = afterDollar.pop();
            const y = tokens[i + 1];
            const res = 3 * x + y + 2;
            afterDollar.push(res);
            i++; // skip next number
        } else {
            afterDollar.push(tokens[i]);
        }
    }

    // Step 3: Evaluate all # from left to right
    let result = afterDollar[0];
    for (let i = 1; i < afterDollar.length; i += 2) {
        const op = afterDollar[i];
        const y = afterDollar[i + 1];
        if (op === '#') {
            result = 2 * result + 3 * y + 4;
        }
    }

    console.log(result);
}



// 测试用例
const cases = [
    `7#6$5#12`,       // 输出226
    `123#4$5#67$78`,  // 正确计算:先处理4$5=3*4+5+2=19,67$78=3*67+78+2=201+78+2=281;再处理123#19=2*123+3*19+4=246+57+4=307;最后307#281=2*307+3*281+4=614+843+4=1461
    `1$2$3`,          // 1$2=3*1+2+2=7,7$3=3*7+3+2=26 → 输出26
    `3#4$5#6`         // 4$5=3*4+5+2=19;3#19=2*3+3*19+4=6+57+4=67;67#6=2*67+3*6+4=134+18+4=156 → 输出156
];

let caseIndex = 0, lineIndex = 0;
const readline = (() => {
    let lines = [];
    return () => {
        if (!lineIndex) lines = cases[caseIndex].trim().split('\n').map(l => l.trim());
        return lines[lineIndex++];
    };
})();

cases.forEach((_, i) => {
    caseIndex = i;
    lineIndex = 0;
    solution3();
    console.log('-------');
});

华为OD试中涉及的“火星文计算”问题通常是指一种特殊的字符串处理任务,其中输入可能包含非标准字符或特定规则下的编码格式。这类题目要求编写程序对输入进行解析,并按照指定规则进行转换或计算。 ### 问题描述 在“火星文计算”相关的编程题中,常见的场景包括: - 输入一串由特殊符号、数字或字母组成的字符串。 - 根据某种规则(如替换表、加减操作、进制转换等)将字符串转换为可读性更强的形式。 - 输出最终结果,可能是数值计算结果或格式化后的字符串。 例如,题目可能会给出一个映射表,将某些符号转换为对应的数字,并要求根据这些规则完成加法或乘法运算。 ### 解题思路 1. **解析输入**:首先需要正确读取输入内容,并理解其结构和规则。例如,输入可能分为多个部分,用分隔符区分操作类型和数据。 2. **构建映射关系**:如果题目提供了火星文与地球文(即常规数字或字符)之间的映射表,则应将其存储在一个字典或哈希表中以便快速查找。 3. **转换与计算**:将火星文转换为标准格式后,执行相应的数学运算。 4. **格式化输出**:将计算结果按要求格式化输出。 ### 示例代码 以下是一个简化版的火星文加法示例代码: 假设火星文中 `A` 表示 `10`,`B` 表示 `20`,`C` 表示 `30`,我们需要实现两个火星文数相加并输出结果。 ```python # 定义火星文到地球文的映射 mars_to_earth = { 'A': 10, 'B': 20, 'C': 30 } # 反向映射,用于将地球文结果转回火星文 earth_to_mars = {v: k for k, v in mars_to_earth.items()} def add_mars_numbers(a, b): # 将输入的火星文转换为地球文数值 num_a = mars_to_earth.get(a, 0) num_b = mars_to_earth.get(b, 0) # 执行加法运算 result = num_a + num_b # 将结果转换回火星文表示 return earth_to_mars.get(result, '?') # 如果没有对应的火星文,返回 ? # 测试示例 print(add_mars_numbers('A', 'B')) # 应输出 C ``` ### 拓展思路 - 如果题目支持多种运算(如加法、减法),可以通过添加运算符判断逻辑来扩展功能。 - 如果火星文表示方式复杂(如多位数、进制转换),则需要引入更复杂的解析制。 - 若火星文字符串长度不固定,可能需要使用正则表达式进行拆分处理。 通过掌握这些基本技巧,可以应对华为OD试中类似“火星文计算”的编程挑战[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值