1.进制
二进制
Binary,缩写bit 比特
二进制 逢2进1, 只有0或1
只有32位 ,最前面一位,0 表示正数,1表示负数\
//代表 1
0000 0000 0000 0000 0000 0000 0000 0001
//代表-1
1000 0000 0000 0000 0000 0000 0000 0001
//js 表达 二进制0b开头
let a = Ob0001 ,或者 Ob00000000000000000000000000000001
八进制
Octal,缩写OCT或O
八进制就是逢8进1,都是0~7的数字,到8就进1位,八进制,
以8为基数的计数法,采用0,1,2,3,4,5,6,7八个数字,逢八进1。
//代表 1
0000 0000 0000 0000 0000 0000 0000 0001
//代表-1
1000 0000 0000 0000 0000 0000 0000 0001
//js 表达 二进制0o开头
let a = Oo0017 ,或者 Oo00000000000000000000000000000001
十进制
由0,1,2、3、4、5、6、7、8、9组成,运算规律是逢十进一;
十六进制
hex, 缩写x
由数字0~9以及字母A,B,C,D,E,F组成,运算规律是逢十六进一
//代表 1
0000 0000 0000 0000 0000 0000 0000 0001
//代表-1
1000 0000 0000 0000 0000 0000 0000 0001
//js 表达 二进制0x开头
let a = Ox001a
进制转化
十进制转换其他进制
NumberObject.toString(radix);
//转二进制
var num = 18;
console.log(num.toString(2)); //10010
var num = -18; //负号保留
console.log(num.toString(2)); //-10010
//转8进制
var num = 18;
console.log(num.toString(8)); //22
var num = -18; //负号保留
console.log(num.toString(2)); //-22
//转16进制
var num = 1200;
console.log(num.toString(16));//4b0
其他进制 转十进制
parseInt(string, radix);
//二进制 转 十进制
parseInt("00100",2) //4
//8进制 转 十进制
parseInt("0011",8) // 9
//16进制 转 十进制
parseInt("0010",16) // 16
parseInt("00f",16) // 15
2.二进制负数 相加
要做 5 - 5 = 0,其实相当于 5 + (-5) = 0 所以只要相加的时候 先做一下转化就ok了
一般要转化为两数的 补码 相加。最终使得相加之和 变成最大数 + 1,如 二进制0b1111111111,再加1,让他溢出,但其他位都已经是 ob000000000,所以结果为0.
原码
符号位 最前面保留的一位,1为负数,0为正数。
原码=符号位+真值。
比如:
[+5]原码=0 0000000 00000000 00000000 00000101
[-5]原码=1 0000000 00000000 00000000 00000101
如果上面直接相加,肯定不等于 0
反码
正数的反码与其原码相同;负数的反码是对其原码逐位取反
[+5]反码=0 0000000 00000000 00000000 00000101
[-5]反码=1 1111111 11111111 11111111 11111010\
补码
补码:正数的补码与原码相同,负数的补码等于其反码的末位加1。
[+5]反码=0 0000000 00000000 00000000 00000101
[-5]反码=1 1111111 11111111 11111111 11111011\
特殊情况:
+0 和 -0 的表示,在原码和反码都有两种形式,但是补码却只有一种:
[+0]=[0000 0000]原=[0000 0000]反=[0000 0000]补
[-0]=[1000 0000]原=[1111 1111]反=[0000 0000]补
测试5 - 5
[+5]补码=0 0000000 00000000 00000000 00000101
[-5]补码=1 1111111 11111111 11111111 11111011
由于相加后,在最前面33位进1,其他都为0,由于只有32位,33位的1溢出,结果还是0,所以5-5 结果为0.
3.位运算-基础篇
- 与(&)
- 或(|)
- 非(~)
- 异或(^)
- 左移(<<)
- 右移(>>)
- 无符号右移(>>>)。
与(&)
两个都为1,才能为1,否则为0
A = 10001001
B = 10010000
A & B = 10000000
或(|)
其中一个为1都为1
A = 10001001
B = 10010000
A | B = 10011001
非(~)
所有位取反
A = 10001001
~A = 01110110
异或(^)
两个一样则为0,不一样则为1
A = 10001001
B = 10010000
A^B = 00011001
左移(<<)
整体左移n位,等价于乘2*n,超出 32 位的值,则自动丢弃
A = 10001001
A<<1 = 100010010
右移(>>)
整体右移n位,等价于除于2*n ,有符号右移位
A = 10001001
A>>1 = 1000100
//实际是
0000 0000 0000 0000 0000 0000 1000 1001
//右移 前面第一位0保留
0000 0000 0000 0000 0000 0000 0100 0100
//如果是负数
1000 0000 0000 0000 0000 0000 1000 1001
//右移 前面第一位1保留
1000 0000 0000 0000 0000 0000 0100 0100
无符号右移(>>>)
右移后左边空出的位用零来填充。移出右边的位被丢弃
当都是正数时,等价于 >> ,当是负数的时候,就会完全不一样。
A = 10001001
A>>>1 = 01000100
//如果是负数
1000 0000 0000 0000 0000 0000 1000 1001
//右移 前面第一位1保留
0100 0000 0000 0000 0000 0000 0100 0100
2.react源码的位运算
export type SideEffectTag = number;
// Don't change these two values. They're used by React Dev Tools.
export const NoEffect = /* */ 0b000000000000;
export const PerformedWork = /* */ 0b000000000001;
// You can change the rest (and add more).
export const Placement = /* */ 0b000000000010;
export const Update = /* */ 0b000000000100;
export const PlacementAndUpdate = /* */ 0b000000000110;
export const Deletion = /* */ 0b000000001000;
export const ContentReset = /* */ 0b000000010000;
export const Callback = /* */ 0b000000100000;
export const DidCapture = /* */ 0b000001000000;
export const Ref = /* */ 0b000010000000;
export const Snapshot = /* */ 0b000100000000;
export const Passive = /* */ 0b001000000000;
// Passive & Update & Callback & Ref & Snapshot
export const LifecycleEffectMask = /* */ 0b001110100100;
// Union of all host effects
export const HostEffectMask = /* */ 0b001111111111;
export const Incomplete = /* */ 0b010000000000;
export const ShouldCapture = /* */ 0b100000000000;
通过或运算就可以 增加权限如或检验
- 新增权限 -> 修改
let permission = Placement //0b000000000010
//只需要把 permission 和 Update 做或运算
ret = permission | Update
// 等价于 求或
// 0b000000000010
// 0b000000000100
// 0b000000000110
- 验证权限 -> 通过求 &
let ret = 0b000000000010 //假设 只有加权限
if(ret & Update == 0) { //校验是否有修改权限
// 等价于 求与
// 0b000000000010
// 0b000000000100
// 0b000000000000 == 0 //确实没有权限
}
3.刷题
136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
答题
- for + map
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
let map = new Map()
for (let i = 0; i < nums.length; i++) {
const item = nums[i];
if(map.has(item)) {
map.set(item,true)
}else {
map.set(item,false)
}
}
for (item of map ) {
if(!item[1]) {
return item[0]
}
}
};
- 遍历+异或 由于本题重复的一定是两个一样的,再加上异或有以下特性:
- a ^ 0 = a
- a ^ a = 0
- a ^ a ^ b = b
var singleNumber = function(nums) {
let ret = 0
for (let i = 0; i < nums.length; i++) {
ret = ret ^ nums[i];
}
return ret
};