【问题标题】:What is 32-bit integer in JavaScript?JavaScript 中的 32 位整数是什么?
【发布时间】:2018-05-15 22:54:57
【问题描述】:

我在做一些编码挑战,遇到了一些我不太熟悉的东西。我更想知道它是什么以及它为什么存在。

提示很简单:

给定一个 32 位有符号整数,反转整数的数字。

Example:
Input: -123
Output: -321

Example:    
Input: 120
Output: 21

Assume we are dealing with an environment which could only hold integers within the 32-bit signed integer range. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

我想出了这个。

var reverse = function(x) {
    var isNegative = false;
    if(x < 0){
        isNegative = true;
        x *= -1;
    };
    var reverseX = parseInt(String(x).split('').reverse((a,b) => a - b).join(''));
    if(reverseX > Math.pow(2,32)){
      return 0;
    }
    if(isNegative){
        return -1 * reverseX
    } else {
        return reverseX;
    }
};

但是,我对一些失败的测试感到困惑:

Input:
1563847412
Output:
2147483651
Expected: 0

据我了解,32 位整数是 2^32。它在 JS 中的意义是什么?如果我开始复习会发生什么? (2^32 + 1)

如果我可以问两个,我的第二个问题是,如果 reverseX 的值超过 2^32,我是否“预期”,但它仍然未通过测试。

if (reverseX > Math.pow(2, 32)) {
  return 0;
}

当我超过 32 位整数时,如何正确返回 0

【问题讨论】:

  • 整数溢出:xkcd.com/571
  • 改变 Math.pow(2, 32) 应该是 Math.pow(2, 31) -1

标签: javascript integer


【解决方案1】:

有符号整数的上界不是 232 - 1,而是 231 - 1,因为第一位是符号位。

如果你进行比较,你会看到你的测试给出了正确的结果。

请注意,JavaScript 使用IEEE-754 floating point 表示数字,即使它们是整数。但是浮点的精度足以对 32 位整数进行精确计算。正如您所意识到的,您需要进行必要的测试来检测 32 位溢出。

关于您的代码的一些注意事项:它将参数传递给Array#reverse 方法,该方法不带参数。以下是我的写法——见代码中的 cmets:

// Name argument n instead of x, as that latter is commonly used for decimal numbers 
function reverse(n) {
    // Array#reverse method takes no argument.
    // You can use `Math.abs()` instead of changing the sign if negative.
    // Conversion of string to number can be done with unary plus operator.
    var reverseN = +String(Math.abs(n)).split('').reverse().join('');
    // Use a number constant instead of calculating the power
    if (reverseN > 0x7FFFFFFF) {
        return 0;
    }
    // As we did not change the sign, you can do without the boolean isNegative.
    // Don't multiply with -1, just use the unary minus operator.
    // The ternary operator might interest you as well (you could even use it
    //    to combine the above return into one return statement)
    return n < 0 ? -reverseN : reverseN;
}

console.log(reverse(-123));
console.log(reverse(1563847412));

更高效

与简单的算术运算相比,转换为字符串、拆分和连接是相对昂贵的操作。因此,解决这样的问题会更节省时间(和内存):

function reverse(n) {
    var reverseN = 0;
    var sign = n < 0;
    n = Math.abs(n);
    while (n) {
        reverseN = reverseN*10 + (n % 10);
        n = Math.floor(n/10);
    }
    return reverseN > 0x7FFFFFFF ? 0 : sign ? -reverseN : reverseN;
}

console.log(reverse(-123));
console.log(reverse(1563847412));

【讨论】:

  • 对您的回答表示敬意:运行时间:84 毫秒,比 83.91% 的反向整数 JavaScript 在线提交要快。内存使用:35.9 MB,不到 56.21% 的反向整数 JavaScript 在线提交。
  • 谢谢你,@Viet!答案并不是真正关注效率,而是解决 OP 遇到的问题。既然您提到了空间和时间效率,我在答案中添加了一个更有效的变体。
  • 谢谢!你怎么知道2^31 -10x7FFFFFFF
  • @vbarinov,二进制表示中的 2^31 是 1 后跟 31 个零(就像十进制中的 10^6 是 1 后跟 6 个零)。每组 4 个二进制数字(从右开始)是一个十六进制数字,所以 2^31 是 0x80000000。然后减一...
  • OP 从来没有提到过 leetcode,也没有提到这个要求。无论如何,所有要求都应该在问题中。 OP 不能假设我们知道他们正在处理 leetcode 挑战,并且我们应该阅读场外内容以完全理解这个问题。我们应该只考虑问题中存在的规范以及 OP 的特定问题。
【解决方案2】:

但是,我对一些失败的测试感到困惑:

Input:
1563847412
Output:
2147483651
Expected: 0

我认为最大的 32 位整数是 (2^31),即 2,147,483,647。这样一来,也可以存储负值 (-2^31) 是 32 位限制(这就是“签名”的意思)。因此,任何高于此的数字,为了您的程序,您都可以返回 0。如果提示要求您输入“未签名”,则范围为 02^32,正如您最初假设的那样。

就您的失败测试而言,21474836512,147,483,647 大 4,因此您应该返回 0。相反,您应该说 reverseX &gt; Math.pow(2,31) - 1

它在 JS 中的意义是什么?如果我开始复习会发生什么? (2^32 + 1)

从技术上讲,在 JS 中你不受这个数字的限制,JS 使用 significand double-precision floating point 数字。所以最大值其实是(2^53) - 1

【讨论】:

  • 奇怪的是 2^31 应该是奇数。
【解决方案3】:

这是我对该问题的解决方案。我不推荐 split().join() 方法,因为它大大增加了时间和空间的复杂性。

// 0(n)
var reverse = function(x) {
  var reverse = 0
  var isNegative = x < 0 ? -1 : 1
  x = x * isNegative

  // capture single digits
  if (x / 10 < 1) {
    return x
  }

  // reverse
  while (x >= 1) {
    var diff = parseInt(x % 10)
    reverse = (reverse * 10) + diff
    x = x / 10
  }

  // capture greater than 32bit
  if (reverse > Math.pow(2,31)-1) {
    return 0;
  }

  // capture negative
  return reverse * isNegative
};

【讨论】:

    【解决方案4】:

    这很好用

    var reverse = function(x) {
            let num = Math.abs(x);
            let result = 0;
            let rem;
            while(num>0){
                rem = num % 10;
                result = result * 10 + rem;
                num = Math.floor(num/10);
            }
            if(0x7FFFFFFF < result) return 0
            if(x < 0) return result * -1;
            return result;
        };
    

    【讨论】:

      【解决方案5】:

      var reverse = function(x) {
        let ans = parseInt(x.toString().split('').reverse().join('').toString());
      
        if (x < 0) { ans *= -1; }
      
        if (ans < (Math.pow(2, 31) * -1) || ans > Math.pow(2, 31) - 1) return 0;
        return ans;
      };
      
      console.log("Reverse of 123: " + reverse(123));
      console.log("Reverse of -123: " + reverse(-123));

      【讨论】:

      • 在与 OP 的问题相关的地方添加两行描述,将为以后访问此答案的每个人提供更广泛的背景。
      • 我会把最后两行合并成一个像这样return (Math.abs(Math.pow(2, 31) - 1) &lt; ans) ? 0 : ans
      【解决方案6】:
      const reverse = x => {
          let possible = x.toString().split('').reverse();
          let temp, sign, overflow;
          if(Number.isNaN(parseInt(possible[possible.length -1]))) {
            sign = possible.pop();
          }   
          temp = parseInt(possible.join(''));
          overflow = temp > 2**31-1;
          if(sign) {
              if(!overflow) {
                  return temp*-1;
              }
          } else {
              if(!overflow){
                 return temp;   
              }    
          }
          return 0;
      };
      

      【讨论】:

        【解决方案7】:
        var reverse = function(x) {
            let isNegative = x < 0 ? -1 : 1    
            x = x * isNegative
            const split = `${x}`.split(``)
            if(split && split.length){
                let reversedInteger = ``
                for(let i=1;i<= split.length;i++) {
                     reversedInteger = reversedInteger + split[(split.length)-i]
                }
                 if (reversedInteger > Math.pow(2,31)-1) {
                     return 0;
                 }
                return parseInt(reversedInteger*isNegative)
            }
        };
        

        运行时间:72 毫秒,比 82.67% 的反向整数 JavaScript 在线提交要快。 内存使用:36 MB,不到 28.12% 的反向整数 JavaScript 在线提交。

        【讨论】:

          【解决方案8】:
          function reverse(x) {
              let strArr = x.toString().split('');
              let initialString = '';
              for (let i = strArr.length - 1; i >= 0; i--) {
                  initialString += strArr[i];
              }
              if (parseInt(initialString) > Math.pow(2, 31) - 1 || parseInt(initialString) < Math.pow(-2, 31)) {
                  return 0;
              } else if (x < 0) {
                  return -parseInt(initialString);
              } else {
                  return parseInt(initialString);
              }
          }
          

          【讨论】:

            【解决方案9】:
            var reverse = function(x) {
                 let reversed = parseInt(Array.from(`${Math.sign(x) * x}`).reverse().join(''));
                 return Math.sign(x)*(reversed > 0x7FFFFFFF?0:reversed);
                
            };
            

            运行时间:96 毫秒,比 73.30% 的 JavaScript 在线提交要快 对于反向整数。内存使用:40.4 MB,不到 38.77% 反向整数的 JavaScript 在线提交。

            虽然不是最佳的空间和时间复杂度。

            【讨论】:

              【解决方案10】:

              已经晚了,但还是想给出答案。

                 var reverse = function(x) {
                 let rev =  parseInt(x.toString().split('').reverse().join(''));
              
                  if(rev > Math.pow(2, 31)){
                   return 0;
                  }
                   else{        
                    return rev*Math.sign(x);
                  }    
                 }
              

              运行时间:88 毫秒,比 95.55% 的反向整数 JavaScript 在线提交要快。 内存使用:40 MB,不到 88.15% 的反向整数 JavaScript 在线提交。

              【讨论】:

                【解决方案11】:
                var reverse = function(x) {
                    var reverseX = parseInt(x.toString().split('').reverse().join(''));
                    if (reverseX < (Math.pow(2, 31) * -1) || reverseX > Math.pow(2, 31) - 1) return 0;
                    return reverseX* Math.sign(x);
                    
                };
                
                • 先将x转成字符串,用''分割,得到数组。

                • 稍后使用数组的reverse()函数来反转数组的元素

                • 使用 join('') 函数再次加入之后 现在,检查如果反转 reverseX 导致值超出有符号的 32 位整数范围 [-231, 231 - 1],则返回 0。

                  if (reverseX Math.pow(2, 31) - 1) 返回 0;

                【讨论】:

                • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票。
                【解决方案12】:

                我已经尝试过这个解决方案。它有 运行时间:84 毫秒,比用于 Reverse Integer 的 98.31% 的 JavaScript 在线提交要快。在 Leetcode 上。

                var reverse = function(x) {
                let minus = false;
                    x < 0 ? minus=true : minus=false;
                    let reverse = parseInt(x.toString().split("").reverse().join(''));
                    if (reverse > Math.pow(2,31) - 1) {
                        return 0;
                    }
                    if(minus){
                      return parseInt(`-${reverse}`)
                    }
                    return reverse
                };
                

                【讨论】:

                  【解决方案13】:

                  这是我的解决方案

                   var reverse = function(x) {
                  
                  
                      rev_string = x.toString()
                      strArray = rev_string.split("")
                      revArray = strArray.reverse()
                      new_str =  revArray.join("")
                  
                      if (parseInt(new_str) < (Math.pow(2, 31) * -1) || parseInt(new_str) > Math.pow(2,31) - 1) {
                           new_str = 0;
                      }
                      if (Math.sign(x) === -1) {
                      
                         new_str = parseInt(new_str) * Math.sign(x);
                      }
                  
                  
                    return new_str;
                    };
                  

                  【讨论】:

                    【解决方案14】:

                    这就是我的做法。

                    var reverse = function(x) {
                        let negative = x < 0;
                        x = parseInt(String(Math.abs(x)).split("").reverse().join(""));
                        return x > 0x7FFFFFFF ? 0 : negative ? -x : x;
                    };
                    

                    【讨论】:

                      【解决方案15】:

                      不幸的是,到目前为止发布的所有解决方案(可能this one 除外)都不正确!包括目前accepted solution。这就是原因。

                      32 位整数的范围从 -2147483648 (-2^31) 到 2147483647 (2^31 − 1)

                      因此,如果我们传入 reverse 函数

                      • -8463847412 - 我们应该得到-2147483648(仍在范围内),但在此处发布的大多数解决方案中,我们得到0,这是错误的!
                      • 8463847412 - 我们应该得到0。此处发布的一些解决方案未能解决此问题,而是显示2147483648,它高于最大 32 位整数限制。

                      这是我的解决方案,也许不是最优雅的,但肯定是最准确的

                      // feel free to use exact values here to optimize performance
                      const minIntegerNumber = Math.pow(-2, 31) // -2147483648
                      const maxIntegerNumber = Math.pow(2, 31) - 1 // 2147483647
                      
                      function reverse(x: number): number {
                        const reversedCharacters = x.toString().split('').reverse().join('')
                        if (x < 0) {
                          const result = Number(`-${reversedCharacters.slice(0, reversedCharacters.length - 1)}`)
                          return result < minIntegerNumber ? 0 : result
                        } else {
                          const result = Number(reversedCharacters)
                          return result > maxIntegerNumber ? 0 : result
                        }
                      }
                      

                      【讨论】:

                        【解决方案16】:

                        我是带着这个来的。不如其他一些答案好,但它有效。

                            function reverse(x) {
                                if(x>0){
                                    x=x.toString();
                                    var v=1;    
                                }
                                else{
                                    x= -1*x;
                                    x= x.toString();
                                    var v=-1;
                                }
                                var newArr = [];
                                for(var i=x.length-1;i>=0;i--){
                                    var index = x.length-1-i;
                                    newArr[index]=x[i];
                                }
                                var result = parseInt(newArr.join('')*v);
                                if(result <=2147483647 && result >= -2147483647){
                                    return result
                                }
                                else{
                                    return 0
                                }
                            };
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2012-07-27
                          • 2010-11-04
                          • 2012-01-12
                          • 1970-01-01
                          • 2013-09-18
                          • 1970-01-01
                          相关资源
                          最近更新 更多