Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
编程世界总是离不了算法
最近在看框架源码时,会有很多算法的实现逻辑,有时候会感到吃力
于是决定蹭着假期,加强算法和数据结构相关的知识
那怎么提升呢?
其实我知道算法这东西没有捷径,多写多练才能提升,于是我开启我的LeetCode刷题之旅
第一阶段目标是:200道,每天1到2篇
为了不乱,本系列文章目录分为三部分:
- 今日题目:xxx
- 我的思路
- 代码实现
今天题目:393. 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 编码的工作方式:
Char. number range | UTF-8 octet sequence (hexadecimal) | (binary) --------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 注意:输入是整数数组。只有每个整数的 最低 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
我的思路
根据题目模拟,从第一个数开始遍历,我们判断每个数的第1位,如果是0代表它只能表示1个字节字符,直接i++继续。如果第1位是1,代表后面的数字要跟当前数字一起组成字符。具体字节取决于当前数字前面有几个1。
注意:
题目说明字符的长度为1 - 4的字节,所以我们要保证当前数前面的1要大于1个,且小于5个。具体用例可以参考: [250,145,145,145,145] 字节为5个,不符合 [128,1,1] 128有1个1,无法代表单字节、多字节 js运算符优先级。(4 & (1 << 7)) === 0 和 4 & (1 << 7) === 0 结果不一样,=== 优先级大于 &
代码实现
/**
* @param {number[]} data
* @return {boolean}
*/
var validUtf8 = function(data) {
// 看第一个字节的首位,是1还是0,0就代表是是一个字节字符。再看下一个字节
// 如果是1,累计几个1,后面几个字节都要以10开头。
let i = 0;
while (i < data.length) {
const current = data[i];
// 首位是0, 代表一个字节
if ((current & (1 << 7)) === 0) {
i++;
} else {
let j = 6; // 注: 本身也算个字节,所以要少算个1
i++;
// 可能最后一个字节首位是1,那就不符合条件
if (i === data.length) {
return false;
}
// 开始从下个字节检查是否以10开头,这过程必须保证current的当前进制位是1
while ((current & (1 << j)) && i < data.length) {
const next = data[i];
if ((next & (1 << 7)) === 0 || (next & (1 << 6)) !== 0) {
return false;
}
j--;
i++;
}
// 注意审题:可能的长度为1到4字节,所以我们判断j是否小于3(6 - 3),是否等于6 返回false
if (j < 3 || j === 6) {
return false
}
// 如果是current当前位置还是1,且i超过data.length。说明多字节字符不符合。
if ((current & (1 << j)) && i >= data.length) {
return false
}
}
}
return true;
};
总结
实现方式其实有很多,这里仅供参考~
由于刚开始刷题,也不知道从哪里刷好,如果前辈们有好的建议,希望不吝赐教,感谢🌹