思路:位运算
- 不要转化成字符串去判断,反复折磨,没必要
- 位运算是最正的解法
- 此题的逻辑是比较复杂的,可以分成几步来进行
- 判断当前int的前缀情况,如果是0,说明是1字节的字符;如果有n个
1
,说明其后有 n - 1 个后续位置(往后读 n - 1 个 int) - 对于后面的 n - 1 个后续位置,分别检查是不是
10
开头的,是10
开头,就说明符合,否则不符合,返回false - 如果一直能读到最后一个位置,说明整个序列没问题,否则有错
- 判断当前int的前缀情况,如果是0,说明是1字节的字符;如果有n个
关于位运算有两点:
class Solution:
"""
此题的逻辑是比较复杂的,可以分成几步来进行
1. 判断当前int的前缀情况,如果是0,说明是1字节的字符;如果有n个1,说明其后有 n - 1 个后续位置(往后读 n - 1 个 int)
2. 对于后面的 n - 1 个后续位置,分别检查是不是10开头的,是10开头,就说明符合,否则不符合,返回false
3. 如果一直能读到最后一个位置,说明整个序列没问题,否则有错
关于位运算有两点:
1. 利用mask1去读有几个前缀的1
2. 利用mask1 和 mask2 去判断是不是10开头的
"""
def validUtf8(self, data: List[int]) -> bool:
mask1 = (1 << 7)
mask2 = (1 << 7) + (1 << 6) - 1
len_data = len(data)
def getDistance(cur_num: int) -> int:
# 说明第一位是0![](https://img-blog-01.oss-cn-shanghai.aliyuncs.com/img/20220324002744.png)
if (cur_num & mask1) == 0:
return 0
# 如果不是0
distance = 0
while (cur_num & mask1) == mask1:
cur_num <<= 1
distance += 1
return distance if 2 <= distance <= 4 else -1
def checkPrefix(cur_num: int) -> bool:
return (cur_num & mask1 == mask1) and (cur_num | mask2 == mask2)
begin_pos = 0
while begin_pos < len_data:
next_dis = getDistance(data[begin_pos])
if next_dis == 0:
begin_pos += 1
elif next_dis == -1:
return False
else:
if begin_pos + next_dis > len_data:
return False
for i in range(begin_pos + 1, begin_pos + next_dis):
if not checkPrefix(data[i]):
return False
begin_pos += next_dis
return True