UTF-8 编码验证
难度:
标签:
题目描述
给定一个表示数据的整数数组 data
,返回它是否为有效的 UTF-8 编码。
UTF-8 中的一个字符可能的长度为 1 到 4 字节,遵循以下的规则:
- 对于 1 字节 的字符,字节的第一位设为 0 ,后面 7 位为这个符号的 unicode 码。
- 对于 n 字节 的字符 (n > 1),第一个字节的前 n 位都设为1,第 n+1 位设为 0 ,后面字节的前两位一律设为 10 。剩下的没有提及的二进制位,全部为这个符号的 unicode 码。
这是 UTF-8 编码的工作方式:
Number of Bytes
| UTF-8 octet sequence | (binary) --------------------+--------------------------------------------- 1 | 0xxxxxxx 2 | 110xxxxx 10xxxxxx 3 | 1110xxxx 10xxxxxx 10xxxxxx 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x
表示二进制形式的一位,可以是 0
或 1
。
注意:输入是整数数组。只有每个整数的 最低 8 个有效位 用来存储数据。这意味着每个整数只表示 1 字节的数据。
示例 1:
输入:data = [197,130,1] 输出:true 解释:数据表示字节序列:11000101 10000010 00000001。 这是有效的 utf-8 编码,为一个 2 字节字符,跟着一个 1 字节字符。
示例 2:
输入:data = [235,140,4] 输出:false 解释:数据表示 8 位的序列: 11101011 10001100 00000100. 前 3 位都是 1 ,第 4 位为 0 表示它是一个 3 字节字符。 下一个字节是开头为 10 的延续字节,这是正确的。 但第二个延续字节不以 10 开头,所以是不符合规则的。
提示:
1 <= data.length <= 2 * 104
0 <= data[i] <= 255
代码结果
运行时间: 31 ms, 内存: 16.4 MB
/*
* 思路:
* 1. 使用流来处理数据数组,依次检查每个字节的头几位,以确定字符的长度。
* 2. 根据字符的长度验证后续字节是否符合 UTF-8 编码规则。
* 3. 如果所有字节都符合 UTF-8 编码规则,则返回 true;否则返回 false。
*/
import java.util.stream.IntStream;
public class Solution {
public boolean validUtf8(int[] data) {
int[] count = {0};
return IntStream.of(data).allMatch(d -> {
if (count[0] == 0) {
if ((d >> 5) == 0b110) {
count[0] = 1;
} else if ((d >> 4) == 0b1110) {
count[0] = 2;
} else if ((d >> 3) == 0b11110) {
count[0] = 3;
} else if ((d >> 7) != 0) {
return false;
}
} else {
if ((d >> 6) != 0b10) {
return false;
}
count[0]--;
}
return true;
}) && count[0] == 0;
}
}
解释
方法:
这个题解采用迭代的方式遍历字节数组,对每个字节进行分析。如果当前字节是一个 UTF-8 编码的开始字节,根据其前缀的 1 的个数确定后续应该有几个字节(用 tail_flag 变量表示)。如果当前字节是一个后续字节,则检查其前两位是否为 10。迭代结束后,如果 tail_flag 为 0,说明所有字节都符合 UTF-8 编码规则。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
在检测字节是否为有效 UTF-8 编码的起始字节时,您是如何决定使用哪些位运算以及这些运算对应的二进制模式是什么?
▷🦆
对于多字节字符的起始字节,为什么需要检查除第一位之外的其余位是否为0,以确定是两字节、三字节还是四字节字符?
▷🦆
如果数组中的数据不完整,例如在一个四字节字符中只包含了两个字节,您的算法如何处理这种情况?
▷🦆
您的算法中如果遇到非法的起始字节或后续字节,会立即返回 False。这种设计是否考虑了所有可能的错误数据情况,还有其他可能的错误情况吗?
▷