10月11日
第一题
题目
- 给定两个整数
a和b,求它们的除法的商a/b,要求不得使用乘号'*'、除号'/'以及求余符号'%' - 整数除法的结果应当截去(
truncate)其小数部分,例如:truncate(8.345) = 8以及truncate(-2.7335) = -2 - 假设我们的环境只能存储 32 位有符号整数,其数值范围是
[−231, 231−1]。本题中,如果除法结果溢出,则返回231 − 1
知识点:
^异或运算符 true(1)异或任何数 其结果=任何数取反 false(0)异或任何书 其结果=任何数越界问题 //32位 最大值: 2^31-1 = 2147483647 //32位 最小值: -2^31 = -2147483648 如果说a的值为负的最小值,b的值为-1将会越界 -2147483647 / -1 = 2147483648 > 2147483647 就会越界//位移运算符,说先需要有原码,补码,反码的知识 注意:位移运算符是会补符号位,而不是固定补0 如果你的符号位为1,那么就会补1 1.左位移运算符 << 例如 5 的二进制写法为 101 使用左移运算符后 5<<1 = 1010 也就是 数字10 的二进制写法 因为你左移动一位,左移运算符会在后面补0所以就变成了10 (你可以把他理解为乘2,但是如果说要进行位移的值是一个小数,那么会先向下取整为整数后再去位移) 2.右位移运算符 >> 例如 5 的二进制写法为 101 使用右位移运算符后 5>>1 = 010 也就是 数字2 的二进制写法 因为你向右移动一位,有运算符会删除最后一位然后在前面补0 (你可以理解为除2(向下取整),但是如果说要进行位移的值是一个小数,那么会先向下取整,然后在进行位移) 3.无符号右移运算符 >>> 例如 -5 的二进制写法为 -101 使用无符号右移运算符后 -5>>>1 = -11 也就是 数字-3 的二进制写法 (具体这里我没有太看明白,但是我也是给他理解为除二然后向下取整,希望有大佬能在评论补充一下感谢!)var divide = function(a, b) { //先声明出来一个最大值和最小值 const INT_MIN = -Math.pow(2, 31) const INT_MAX = Math.pow(2, 31) - 1 //判断a是否等于最大值且b等于-1 为了防止越界 if (a == INT_MIN && b == -1){ //如果是的话直接返回最大值 return INT_MAX } //判断我们的值是正数还是负数 const sign = (a > 0) ^ (b > 0) ? -1 : 1 //获取到a和b的绝对值 //如果a或者b是最小值的话,那么你取的绝对值还是最小值 a = Math.abs(a) b = Math.abs(b) //声明一个变量用来记录次数 let res = 0 //为什么要循环31次?因为最大值和最小值都是31次方 for (let x = 31; x >= 0; x--) { //采用右移的原因是 右移永远不会越界 //因为a要右移x位 如果 a为最小值,那么使用右移运算符就会变成一个负数 //所以要使用无符号右移运算符,将其变成一个稳定的正数 //他和右移的值是一样的,但是右移是负数,而无符号右移是正数 //这里为什么要 - b ? 因为你一个值右移多少值去减去最小值那么永远都是小于0的 //所以他就会一直返回false 就比如 1-(-2147483647) //我在控制台去 console.log(1-(-2147483647)) 他的结果是 2147483648 //但是在cmd中返回的就是负的最小值,是因为在 32 位中 2147483648 是越界了的 //所以会返回最小值 -2147483647 if ((a >>> x) - b >= 0) { //如果结果为true就去计算 a-(b<<x)位 //但是这行我实际上还不是很明白 a = a - (b << x) //res这里是用来计算当前的商是多少的 res = res + (1 << x) } } if (res == -2147483648) return -2147483648 // bug 修复:因为不能使用乘号,所以将乘号换成三目运算符 return sign == 1 ? res : -res };
总结
今天是
第一遍刷题第一天,感觉蛮吃力其实,算法的基础很差,今天学会了异或运算符和左移/右移运算符,至于无符号运算符我目前的理解还处于在他只会补0 前面两个是会补符号位。如果注释有什么错误,希望各位大佬在评论区指出,我去改正,非常感谢!