| 题目 | TLV编码 |
| 难度 | 易 |
| 题目说明 | TLV编码是按 [Tag Length Value] 格式进行编码的,一段码流中的信元用 Tag 标识,Tag 在码流中唯一不重复,Length 表示信元Value的长度,Value 表示信元的值。 码流以某信元的 Tag 开头,Tag 固定占一个字节,Length 固定占两个字节,字节序为小端序。 现给定 TLV 格式编码的码流,以及需要解码的信元 Tag,请输出该信元的 Value。 输入码流的 16 机制字符中,不包括小写字母,且要求输出的 16 进制字符串中也不要包含小写字母;码流字符串的最大长度不超过 50000 个字节。 |
| 输入描述 | 输入的第一行为一个字符串,表示待解码信元的 Tag; 输入的第二行为一个字符串,表示待解码的 16 进制码流,字节之间用空格分隔。 |
| 输出描述 | 输出一个字符串,表示待解码信元以 16 进制表示的 Value。 |
| 补充说明 | 无 |
| --------------------------------------------------------------------------------------- | |
| 示例 | |
| 示例1 | |
| 输入 | 31 32 01 00 AE 90 02 00 01 02 30 03 00 AB 32 31 31 02 00 32 33 33 01 00 CC |
| 输出 | 32 33 |
| 说明 | 需要解析的信元的 Tag 是 31,从码流的起始处开始匹配,Tag 为 32 的信元长度为 1 (01 00,小端序表示为 1); 第二个信元的 Tag 是 90,其长度为 2; 第三个信元的 Tag 是 30,其长度为 3; 第四个信元的 Tag 是 31,其长度为 2(02 00),所以返回长度后面的两个字节即可,即 32 33。 |
题目解读:
题目中,有两行输入。其中第二行是 TLV 信息流。TLV 信息流由多个信元组成,每个信元又由 Tag、Length、Value 组成;第一行是 Tag,即一个 TLV 信元的 Tag。
题目要求从第二行的多个信元中,找到第一行的 Tag 所对应的信元。然后输出此信元的 Value。
在输入示例中,第一行指定了信元的 Tag 是31,第二行输入的信息流包含了 5个 信元,依次为32、90、30、31、33。我们找到 Tag 为 31 的信元,它为 31 02 00 32 33,其中 31 是 Tag,02 00(即2)是长度,那么其紧跟的 2 个字节 32 33 为 Value,所以最终的结果输出为 32 33。
分析与思路:
此题根据指定的 Tag,从信息流中找到对应的信息员,输出其 Value即可,并不涉及太复杂的逻辑算法。实现如下:
1. 记录第一行输入的数字,设为变量 Tag。
2. 逐一遍历第二行输入的信息流。遍历时,先判断第一个输入是否等于tag:
此算法只需要遍历一次第二行的输入,时间复杂度为 O(n),只需要2个额外的辅助变量,空间复杂度为 O(1)。
Java代码
- import java.util.Scanner;
-
- /**
- * TLV解码
- * @since 2023.09.04
- * @version 0.2
- * @author Frank
- *
- */
- public class LTV_Solution {
- public static void main(String[] args) {
- Scanner sc = new Scanner(System.in);
- while (sc.hasNext()) {
- // 第一行输入的tag
- String tag = sc.nextLine();
-
- // 第二行输入的TLV数据流
- String stream = sc.nextLine();
- String[] tlvStream = stream.split(" ");
- processLTVSolution( tag, tlvStream );
- }
- }
-
- private static void processLTVSolution( String tag, String tlvStream[] )
- {
- int i = 0;
- while (i < tlvStream.length) {
- String tagTmp = tlvStream[i];
-
- String lengthStr = tlvStream[i + 2] + tlvStream[i + 1];
- int length = Integer.parseInt(lengthStr, 16);
-
- // 已找到,输出
- if ( !tagTmp.equals( tag )) {
- // 没有找到Tag,略过,寻找下一个
- i += ( 3 + length);
- continue;
- }
- StringBuilder outputSB = new StringBuilder();
- for (int j = 0; j < length; j++) {
- outputSB.append(tlvStream[i + j + 3]);
- if (j != length - 1) {
- outputSB.append(" ");
- }
- }
- System.out.println(outputSB.toString());
- return;
- }
- }
- }
JavaScript代码
- const rl = require("readline").createInterface({ input: process.stdin });
- var iter = rl[Symbol.asyncIterator]();
- const readline = async () => (await iter.next()).value;
- void async function() {
- while (line = await readline()) {
- // 第一行数据
- var tag = line;
- // 第二行数据转换成数组
- line = await readline();
- var ltvs = line.split(" ");
- processLTVSolution(tag, ltvs);
- }
-
- }();
-
- function processLTVSolution(tag, ltvs) {
- var i = 0;
- while (i < ltvs.length) {
- var tagTmp = ltvs[i];
- var lengthStr = ltvs[i + 2] + ltvs[i + 1];
- var length = parseInt(lengthStr, 16);
-
- // 没有找到Tag,略过,寻找下一个
- if (tagTmp != tag) {
- i += (3 + length);
- continue;
- }
-
- // 已找到,输出
- var output = "";
- for (var j = 0; j < length; j++) {
- output += (ltvs[i + j + 3]);
- if (j != length - 1) {
- output += " ";
- }
- }
- console.log(output);
- return;
- }
- }
(完)