コーディングの挑戦をしていましたが、あまり馴染みのないものに遭遇しました。それが何であるか、なぜそこにあるのかを知りたい。
プロンプトはとても簡単です:Given a 32-bit signed integer, reverse digits of an integer.
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
)
2番目の質問は、reverseX
の値が2 ^ 32を超えると「予想」されますが、まだテストに失敗しています。
if(reverseX > Math.pow(2,32)){
return 0;
}
32ビット整数を超えたときに0
を適切に返すにはどうすればよいですか?
signed整数の上限は2ではありません32 -1、ただし231 -1、最初のビットは符号ビットであるため。
その比較を行うと、テストで正しい結果が得られることがわかります。
JavaScriptでは、数値が整数であっても IEEE-754浮動小数点 表現を使用することに注意してください。しかし、浮動小数点の精度は、32ビット整数で正確な計算を実行するには十分です。気づいたら、32ビットのオーバーフローを検出するために必要なテストを行う必要があります。
コードに関するいくつかの注意事項:引数を Array#reverse
メソッドに渡します。これは引数をとらないメソッドです。ここに私がそれを書く方法があります-コードのコメントを見てください:
// 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));
しかし、私はいくつかの失敗したテストに困惑しています:
_Input:
1563847412
Output:
2147483651
Expected: 0
_
私が信じる最大32ビット整数は_(2^31)
_で、2,147,483,647です。これは、32ビットの制限である_(-2^31)
_と同様に負の値を格納できるようにするためです(これが「署名」の意味です)。したがって、それより大きな数値であれば、プログラムのために0を返すことができます。プロンプトで「符号なし」を要求された場合、範囲は最初に想定したように_0
_〜_2^32
_になります。
失敗したテストに関しては、_2147483651
_は_2,147,483,647
_より4大きいため、0を返す必要があります。代わりにreverseX > Math.pow(2,31) - 1
と言う必要があります
JSでのその重要性は何ですか?また、始めた場合はどうなりますか? (2 ^ 32 + 1)
技術的には、JSではこの数に制限されません。JSは 仮数倍精度浮動小数点 数を使用します。したがって、実際の最大値は_(2^53) - 1
_です
var reverse = function(x) {
let ans;
if (parseInt(x) < 0) {
ans = parseInt(x.toString().split('').reverse().join('').toString()) * -1;
} else {
ans = parseInt(x.toString().split('').reverse().join('').toString());
}
if (ans < (Math.pow(2, 31) * -1) || ans > Math.pow(2, 31) - 1) return 0;
return ans;
};
これはうまくいく
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;
};
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;
};
ここにその質問に対する私の解決策があります。 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
};