(1)给定一个十进制,求Protocol Buffers的 Varint编码;给定一个16进制的 ZigZag编码,求原码;
代码语言:javascript复制const readline = require('readline');
const rl = readline.createInterface({
input : process.stdin,
output : process.stdout
})
rl.question('请输入要转换的值:', function(answer) {
if (/^d $/.test(answer)) {
var str = encode(answer);
console.log(answer ' 的 varint 二进制是:' str);
} else {
console.log('input is error. please input again.')
}
rl.close();
});
function encode(num) {
// 0x80 的二进制表示是 1000 0000, 通过 | 运算最高位补 1
var MSB = 0x80;
// 0x7F的二进制表示是 0111 1111
var REST = 0x7F;
var MSBALL = ~REST;
var out = [];
var offset = 0;
while (num & MSBALL) {
out[offset ] = ((num & 0xFF) | MSB).toString(2);
num >>>= 7;
}
out[offset] = ('00000000' (num | 0).toString(2)).slice(-8);
return out;
}
参考链接:https://github.com/chrisdickinson/varint/blob/master/encode.js
给定ZigZag编码后的值,求原值。
代码语言:javascript复制/*
关于ZigZag编码:
正数
假设数据类型为byte的正数11,其二进制表示为: 00001011
数据左移一位: 00010110
符号位(正数的符号为0)放到最后一位: 00010110
负数
假设数据类型为byte的负数-11,其二进制在计算机中是用补码表示的,计算过程如下
正数原码: 00001011
反码: 11110100
补码(反码加1): 11110101
处理过程:
左移一位: 11101010
符号位放到最后一位: 11101011
除最后一位外全部取反: 00010101
*/
function encode32(n) {
return (n << 1) ^ (n >> 31);
}
function decode32(n) {
return (n >>> 1) ^ -(n & 1);
// return (n >> 1) ^ (~(n & 1) 1);
}
~(function() {
var arr = [parseInt(0x268cb43, 16), parseInt(0x7ff, 16), parseInt(0x2b7b, 16), parseInt(0x123a, 16), parseInt(0xf6, 16), parseInt(0x282, 16)];
// var arr = [parseInt('00010110', 2), parseInt('00010101', 2)];
// var arr = [parseInt('1000000010000100010001000010001', 2)];
for (var i = 0, len = arr.length; i < len; i ) {
var a = decode32(arr[i]);
var b = encode32(a);
console.log(a, b, arr[i])
}
})();
(2)跳跃游戏 —— 对应 Leetcode 第55题
代码语言:javascript复制const readline = require('readline');
const rl = readline.createInterface({
input : process.stdin,
output : process.stdout
});
rl.question('请输入值:', function(answer) {
rl.close();
var str = answer.slice(1, -1);
if (!/^d. d$/.test(str)) {
console.log('输入错误');
return;
}
var arr = str.split(',');
var result = canJump(arr);
console.log(result ? 'true' : 'false');
});
// https://allenmistake.top/2019/04/20/leetcode55dp/
function canJump(arr) {
for (var i = 0, len = arr.length; i < len; i ) {
arr[i] = parseInt(arr[i], 10);
}
var lastPos = arr.length -1;
for (var i = arr.length - 1; i >= 0; i--) {
if (i arr[i] >= lastPos) {
lastPos = i;
}
}
return lastPos == 0;
}
(3)伪随机分布算法(PRD preudo-random distribution)
P(N) = C · N,给定 P 或 C值 求对应的 C/P值
代码语言:javascript复制const readline = require('readline');
const rl = readline.createInterface({
input : process.stdin,
output : process.stdout
});
rl.question('请输入 P 的值:', function(answer) {
rl.close();
if (!/%$/.test(answer)) {
console.log('输入错误');
return ;
}
var result = P2C(answer);
console.log(result)
});
// http://www.yoonper.com/post.php?id=104
function P2C(P) {
// 先计算出次数
P = parseFloat(P) * 0.01;
var low = 0;
var high = P;
var last = 0;
var min = 1 / Math.pow(10, 14);
while (true) {
// 二分查找
var middle = (high low) / 2;
var pr = parseFloat(C2P(middle)) * 0.01;
if (Math.abs(pr - last) <= min) break;
pr > P ? (high = middle) : (low = middle);
last = pr;
}
return Math.floor(middle * 100) '%';
}
function C2P(C) {
var expectationP = 0;
var successP = 0;
var currentP = 0;
// C * N >= 100;
var times = Math.ceil(1 / C);
for (var n = 1; n <= times; n ) {
currentP = (1 - successP) * Math.min(1, C * n);
successP = currentP;
expectationP = currentP * n;
}
return Math.round(1 / expectationP * 100) '%';
}
(4)给定16进制的输入,判断它是否为有效的 UTF-8序列;以及给定一串16进制,判断里面包含几个 Unicode字符
代码语言:javascript复制const readline = require('readline');
const rl = readline.createInterface({
input : process.stdin,
output : process.stdout
});
rl.question('请输入值:', function(answer) {
rl.close();
var arr = answer.split(',');
var binaryArr = [];
for (var i = 0, len = arr.length; i < len; i ) {
binaryArr.push(parseInt(arr[i], 16));
}
var result = validUTF8(binaryArr);
console.log('result : ', result ? '1' : '0');
var cnt = calcAmount(binaryArr);
console.log('amount :', cnt);
});
// https://www.cnblogs.com/grandyang/p/5847597.html
// https://leetcode.com/problems/utf-8-validation/discuss/87464/Bit-Manipulation-Java-6ms
function validUTF8(arr) {
if (arr.length < 1) return false;
var left = 0;
for (var i = 0, len = arr.length; i < len; i ) {
var d = arr[i];
if (left == 0) {
if ((d >> 5) == 0b110) left = 1; // 后面跟一个字节 110xxxxx 10xxxxxx
else if ((d >> 4) == 0b1110) left = 2; // 后面跟二个字节 1110xxxx 10xxxxxx 10xxxxxx
else if ((d >> 3) == 0b11110) left = 3; // 后面跟三个字节 11110xxx 10xxxxxx 10xxxxxx
else if ((d >> 7) == 1) return false;
} else {
if ((d >> 6) != 0b10) return false; // 非标识符不是以 10 开头
--left;
}
}
return left == 0;
}
function calcAmount(arr) {
var count = 0;
for (var i = 0, len = arr.length; i < len; i ) {
var d = arr[i];
// 以 0 开头且
if ((d >> 7) == 0) {
count ;
continue;
}
if ((d >> 5) == 0b110) {
// 以110开头
if ((i 1 < arr.length) && (arr[i 1] >> 6) == 0b10) {
count;
i = 1;
}
} else if ((d >> 4) == 0b1110) {
// 以1110开头
if (
(i 2 < arr.length) &&
(arr[i 1] >> 6) == 0b10 &&
(arr[i 2] >> 6) == 0b10
) {
count;
i = 2;
}
} else if ((d >> 3) == 0b11110) {
if (
(i 3 < arr.length) &&
(arr[i 1] >> 6) == 0b10 &&
(arr[i 2] >> 6) == 0b10 &&
(arr[i 3] >> 6) == 0b10
) {
count;
i = 3;
}
}
}
return count;
}
(5)求某个数是否为2的整数次幂
最简单的核心代码 return (n & (n –1)) == 0
2的1次方为2,二进制表示为10
2的2次方为4,二进制表示为100
2的3次方为8,二进制表示为1000
…
也就是说2的次方,它最高位为1其它位是0,通过-1进行 & 运算,应该正好全部为0
=========================
刷完这些题目,将以前的基础知识再回顾一遍。
<< 左移运算符, <<1 相当于原值乘以2(正数)
>> 右移运算符,>>1 相当于原值除以2(正数)
>>> 无符号右移,忽略符号位
举例说明:
以 6 为位,对应二进制 110,左移一位 1100(对应整数12),右移一位 11(对应整数3)
-6,对应的二进制(32位表示)11111111 11111111 11111111 11111010
正数6的二进制(32位)
00000000 00000000 00000000 00000110
所有位取反
11111111 11111111 11111111 11111001
然后 1(补码)
11111111 11111111 11111111 11111010
<< 左移,后边始终补0
>>如果是正数前面补0,如果是负数前面补1,-7 >> 1 = –4, -7 >> 2 = –2, –7 >> 3 = –1, -7 >> 4 = –1, –7 >> 5 = –1,最高位始终为1(即负数)
>>>无符号右移,无论正负数,前面都补0,负数无符号右移后变成一个很大的正数。 –7 >>> 1 = 2147483644(二进制表示为 01111111 11111111 11111111 11111100)