华为OD机考算法题:TLV解码

目录

题目部分

解析与思路

代码实现


题目部分

题目 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:

  • 如果等于 Tag,则继续遍历接下来的 2 个字节,(根据小端序)计算长度,设为变量 length,然后输出接下来的 length 个字节,即为最终输出。输出后退出程序。
  • 如果不等于 Tag,则继续遍历接下来的2个字节,计算长度,设为变量 length,然后跳过接下来的 length 个字节,然后继续步骤 2。

此算法只需要遍历一次第二行的输入,时间复杂度为 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;
    }
}

(完)

猜你喜欢

转载自blog.csdn.net/ZiJinShi/article/details/132668464