题目

类型:位运算

image.png

解题思路

从前往后处理每个 data[i] ,先统计 data[i] 从第 7 位开始往后有多少位连续的 1,代表这是一个几字节的字符,记为 cntcnt :

  • 如果 cntcnt 为 1 或者大于 4 均违反编码规则(与字符长度为 1 时的编码规则 和 字符长度只能是 1 到 4 冲突),返回 False;
  • 如果位置 i 后面不足 cnt - 1 也返回 False;
  • 否则检查下标范围为 [i + 1, i + cnt - 1] 的数是否满足前两位为 10 的要求,若不满足返回 False。

如果上述过程满足要求,跳到下一个检查点进行检查,整个 data 都没有冲突则返回 True。

代码

  1. class Solution {
  2. public boolean validUtf8(int[] data) {
  3. int n = data.length;
  4. //0 <= data[i] <= 255(二进制中为11111111,8bit=1byte),所以每个data[i]占1个字节
  5. //满足条件的头字节有:0xxxxxxx 110xxxxx 1110xxxx 11110xxx
  6. for (int i = 0 ; i < n ; ) {
  7. int t = data[i];
  8. //1.校验头字节
  9. int j = 7, cnt = 0; //cnt为头字节中开头1的数量
  10. while(j >= 0 && ((t >> j) & 1) == 1 && ++cnt >= 0) j--;
  11. //开头要么是0个1(即1个0),要么是2-4个1
  12. if (cnt == 1 || cnt > 4) return false;
  13. //2.头字节后面的字节数小于 cnt-1个
  14. if (i + cnt - 1 >= n) return false;
  15. //3.判断头字节后的cnt-1个字节前两位开头是否为10
  16. for (int k = i + 1 ; k < i + cnt ; k++) {
  17. if (((data[k] >> 7) & 1) == 1 && ((data[k] >> 6) & 1) == 0) continue;
  18. return false;
  19. }
  20. //4.当前的字符满足规则,继续向后判断
  21. //如果cnt=0,即为题目说的1字节的字符,则当前data[i]为一个有效的unicode
  22. if (cnt == 0) i++;
  23. //cnt不为0,向后移动cnt个字符
  24. else i += cnt;
  25. }
  26. return true;
  27. }
  28. }