信号解码
问题背景
无线基站会接收到手机上报的特定格式的加密信息,例如 11@2$3@14。在处理这些信息之前,需要根据一套固定的规则对其进行解码和计算。
解码规则
信息由非负整数和两种特殊运算符 (@, $) 构成。解码规则如下:
-
运算符定义:
- 对于
x@y,其计算公式为:x@y=2x+y+3 - 对于
x$y,其计算公式为:x$y=3x+2y+1 - 其中
x和y均为非负整数。
- 对于
-
运算优先级:
- 运算符
@的优先级 高于 运算符$。 - 在计算整个表达式时,需要先完成所有
@运算,再进行$运算。
- 运算符
-
计算顺序:
- 对于 相同 的运算符,计算顺序为 从左到右。
输入格式
-
message: 一个字符串,代表待解码的加密信息。-
输入字符串仅包含数字字符 (
0-9) 和特殊运算符 (@,$)。 -
字符串长度
message.length满足3 <= message.length <= 100。 -
用例保证:
- 输入合法,运算符 (
@,$) 的左右两侧必定是数字。 - 数字没有前导零(例如,不会出现
07)。 - 不会出现
4@$5这样运算符相邻的格式。 - 输入的数字、计算过程中的中间值以及最终结果,其取值范围都在
[0, 2^31 - 1]之内。
- 输入合法,运算符 (
-
输出格式
- 一个整数,表示解码和计算后的最终结果。
样例说明
样例 1
-
输入:
"11@2$3@14" -
输出:
128 -
计算过程分解:
-
分析: 表达式中包含
@和$两种运算符。根据优先级规则,首先从左到右计算所有@运算。 -
计算第一个
@:11@2- 套用公式 x@y=2x+y+3
- 2×11+2+3=22+2+3=27
- 原表达式变为:
27$3@14
-
计算第二个
@:3@14- 套用公式 x@y=2x+y+3
- 2×3+14+3=6+14+3=23
- 原表达式变为:
27$23
-
计算
$:27$23- 所有
@运算已完成,现在计算$。 - 套用公式 x$y=3x+2y+1
- 3×27+2×23+1=81+46+1=128
- 所有
-
最终结果:
128
-
样例 2
-
输入:
"103$104@105@2$106@107" -
输出:
5397 -
计算过程分解:
-
分析: 同样,先计算所有
@运算。表达式中有三个@运算:104@105,... @2(前一步的结果),和106@107。 -
计算
104@105@2:-
这是一个连续的
@运算,按从左到右的顺序进行。 -
第一步:
104@105- 2×104+105+3=208+105+3=316
-
第二步:
316@2(用上一步的结果316作为x)- 2×316+2+3=632+2+3=637
-
-
计算
106@107:- 2×106+107+3=212+107+3=322
-
替换原表达式: 将所有
@的计算结果代回,原表达式变为103$637$322。 -
计算
103$637$322:-
这是一个连续的
$运算,按从左到右的顺序进行。 -
第一步:
103$637- 3×103+2×637+1=309+1274+1=1584
-
第二步:
1584$322(用上一步的结果1584作为x)- 3×1584+2×322+1=4752+644+1=5397
-
-
最终结果:
5397
-
/**
* 解决“信号解码”问题的实现类.
* 核心思想是根据运算符优先级,分两步进行计算。
*/
public class SignalDecoder {
/**
* 主方法,对给定的消息字符串进行解码和计算.
* @param message 包含数字和特殊运算符(@, $)的字符串
* @return 最终的计算结果
*/
public int decode(String message) {
// --- 步骤 1: 处理高优先级的 '@' 运算 ---
// 使用 '$' 作为分隔符,将原始表达式分割成多个子表达式。
// 每个子表达式要么是一个纯数字,要么是一个仅包含 '@' 运算符的表达式。
// 注意:String.split() 的参数是正则表达式,'$' 是特殊字符,表示结束位置,需要用 "\$" 来转义。
String[] atExpressions = message.split("\$");
// 创建一个数组来存储处理完 '@' 运算后的中间结果。
// 这些结果将成为 '$' 运算的操作数。
long[] dollarOperands = new long[atExpressions.length];
for (int i = 0; i < atExpressions.length; i++) {
// 对每个子表达式调用辅助方法进行计算
dollarOperands[i] = calculateAtExpression(atExpressions[i]);
}
// --- 步骤 2: 处理低优先级的 '$' 运算 ---
// 如果只有一个操作数(即原始表达式中没有'$'),那么它就是最终结果。
if (dollarOperands.length == 1) {
return (int) dollarOperands[0];
}
// 以第一个操作数作为初始结果
long finalResult = dollarOperands[0];
// 从左到右,依次将后续的操作数通过 '$' 运算累积到结果中
for (int i = 1; i < dollarOperands.length; i++) {
long nextOperand = dollarOperands[i];
// 应用公式: x$y = 3*x + 2*y + 1
finalResult = 3 * finalResult + 2 * nextOperand + 1;
}
// 将 long 类型的最终结果转换为 int 并返回
return (int) finalResult;
}
/**
* 辅助方法:计算一个只包含 '@' 运算符的子表达式的值.
* @param expr 一个子表达式,例如 "104@105@2" 或 "103"
* @return 该子表达式的计算结果
*/
private long calculateAtExpression(String expr) {
// 使用 '@' 作为分隔符,将子表达式分割成纯数字字符串
String[] numbersStr = expr.split("@");
// 将第一个数字作为计算的初始值
// 使用 long 类型进行计算,以防止中间过程溢出,这是一种良好的编程习惯。
long result = Long.parseLong(numbersStr[0]);
// 如果只有一个数字(即子表达式中没有'@'),直接返回该数字
if (numbersStr.length == 1) {
return result;
}
// 从左到右,依次将后续的数字通过 '@' 运算累积到结果中
for (int i = 1; i < numbersStr.length; i++) {
long nextOperand = Long.parseLong(numbersStr[i]);
// 应用公式: x@y = 2*x + y + 3
result = 2 * result + nextOperand + 3;
}
return result;
}
}