在问 · 算法题解

393. UTF-8 编码验证

题目描述

输入整数数组 data,每个元素只有最低 8 位有效,代表一个字节。判断这串字节是否是合法的 UTF-8 编码。合法返回 true,否则返回 false。

UTF-8 中一个字符占 1 到 4 个字节。单字节字符的最高位是 0,格式为 0xxxxxxx。

占 n 个字节(n 为 2、3 或 4)的字符:首字节最高的 n 位都是 1,紧接着一位是 0;后面跟 n - 1 个续字节,每个续字节的最高两位都是 10。其余的 x 位任意。

具体为:2 字节 110xxxxx 10xxxxxx;3 字节 1110xxxx 后接两个 10xxxxxx;4 字节 11110xxx 后接三个 10xxxxxx。整串数据必须恰好被切分成若干个合法字符。

示例 1
输入:data = [197,130,1]
输出:true

解释:字节为 11000101 10000010 00000001:一个 2 字节字符加一个 1 字节字符。

示例 2
输入:data = [235,140,4]
输出:false

解释:首字节 11101011 要求后跟两个续字节,但第三个字节 00000100 不以 10 开头。

数据范围

  • 1 <= data.length <= 2 * 10^4
  • 0 <= data[i] <= 255

解题思路

从左到右扫描,用 need 记录当前字符还缺几个续字节。need 为 0 时,当前字节必须是首字节,用右移看前缀判断字符长度并设置 need;need 大于 0 时,当前字节必须以 10 开头,然后 need 减 1。扫描结束时 need 必须为 0,否则最后一个字符不完整。

为什么正确

处理完每个字节后,已扫描部分是若干完整字符加上一个缺 need 个续字节的未完成字符。

复杂度分析

时间 O(n),空间 O(1)。

易错点

首字节判断要按顺序比较完整前缀:10xxxxxx 不能作为首字节,11111xxx 也非法;循环结束后别忘了检查 need == 0。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def validUtf8(self, data: List[int]) -> bool:
        need = 0
        for x in data:
            if need == 0:
                if x >> 7 == 0:
                    continue
                elif x >> 5 == 0b110:
                    need = 1
                elif x >> 4 == 0b1110:
                    need = 2
                elif x >> 3 == 0b11110:
                    need = 3
                else:
                    return False
            else:
                if x >> 6 != 0b10:
                    return False
                need -= 1
        return need == 0

载入编辑器,自己跑一遍 →

位运算 专题的其他题目

查看 位运算 全部题目 →