私は古い質問を解決しようとしていました:
2つの[整数]の数値AとBを加算する関数を記述します。+や算術演算子は使用しないでください。
最良の解決策は次のようになり、 " LintCode-A + B Problem "から引用されます。
任意の基数のa + bの場合、プラスを2つの部分として扱うことができます。1。キャリーなしのa + b; 2. + bによって生成されたキャリー。その場合、a + bはパート1とパート2の合計に等しくなります。part1+ part2がさらにキャリーを生成する場合は、キャリーがなくなるまでこの手順を繰り返すことができます。
私はこのアルゴリズムを理解でき、すべてが良さそうなので、以下にコードを貼り付けて lintcode でテストしました。
class Solution:
"""
@param a: The first integer
@param b: The second integer
@return: The sum of a and b
"""
def aplusb(self, a, b):
while b != 0:
carry = a & b
a = a ^ b
b = carry << 1
return a
しかし、驚くべきことに、テストケースTime Limit Exceeded
で[100, -100]
エラーが発生しました。そこで、ローカルで実行し、ループごとにa、bを出力します。
(-8, 8)
(-16, 16)
(-32, 32)
(-64, 64)
(-128, 128)
(-256, 256)
(-512, 512)
(-1024, 1024)
(-2048, 2048)
(-4096, 4096)
(-8192, 8192)
(-16384, 16384)
(-32768, 32768)
(-65536, 65536)
(-131072, 131072)
...
計算は正しいので、このアルゴリズムはそのような入力では機能しないと思いますが、C++で同じアルゴリズムを記述した場合、それは機能します。
class Solution {
public:
int aplusb(int a, int b) {
while (b!=0){
int carry = a & b;
a = a^b;
b = carry << 1;
}
return a;
}
};
正確に何を尋ねるべきかわかりません。基本的に質問は次のとおりです。
0
を提供するのに、Pythonは提供しないのはなぜですか?-4
の2の補数表現は次のとおりです。
...11100
はい、私は本当に左側に無限に多くの1
を意味します。これは2進数の繰り返し数字です。技術的には、4
も繰り返し数字です。
...00100
左に0
を繰り返しているだけです。
あなたの足し算の問題は
...11100
+ ...00100
--------------------
...00000
演算子^
、<<
、および&
は、無限に多くの2進数で問題なく計算できますが、問題は、無限に多くの桁上げがあり、それらを計算していることです一度に1桁。これは決して終わらないでしょう。
したがって、このアルゴリズムがこの状況でスタックする時期を認識し、それを説明するために何か他のことをする必要があります。
たとえば、int
が32ビットの場合、右端の31桁を除くすべての桁が1つのビットに折りたたまれるので、C/C++ではこの問題は発生しません。残りのキャリーは一度に行います。
ただし、技術的に言えば、int
を左シフトすることの意味は、ビットパターンではなく整数としての値であるため、2つがあれば未定義の振る舞いを呼び出します。最上位ビットcarry
は常に異なります。これは、carry << 1
がオーバーフローを生成するためです)。
問題は負の数、またはそれらがどのように表されるかです。 In Python整数は任意の精度ですが、C++ intは32ビットまたは64ビットです。したがって、Pythonでは、減算などの負の数を個別に処理するか、手動でビット数を制限する必要があります。
@Hurkylによるすばらしい説明に続いて、pythonが無限の2の補数表現を実装しているという事実を使用して、a=4
およびb=-4
のアルゴリズムをステップスルーしました。
Step 0:
a = ...(0)...000100
b = ...(1)...111100
carry = a & b = ...(0)...000100
a = a ^ b = ...(1)...111000
b = carry << 1 = ...(0)...001000
Step 1:
a = ...(1)...111000
b = ...(0)...001000
carry = a & b = ...(0)...001000
a = a ^ b = ...(1)...110000
b = carry << 1 = ...(0)...010000
Step 2:
a = ...(1)...110000
b = ...(0)...010000
carry = a & b = ...(0)...010000
a = a ^ b = ...(1)...100000
b = carry << 1 = ...(0)...100000
32ビットの符号付き2の補数整数のようなものをエミュレートするには、効果的なカットオフが必要であることは明らかです。キャリービットが最高ビットを超えてバブルアップしたら、アルゴリズムを停止する必要があります。以下が機能しているようです。
MAX_BIT = 2**32
MAX_BIT_COMPLIMENT = -2**32
def aplusb(a, b):
while b != 0:
if b == MAX_BIT:
return a ^ MAX_BIT_COMPLIMENT
carry = a & b
a = a ^ b
b = carry << 1
return a
結果:
>>> aplusb(100,-100)
0
>>> aplusb(100,-99)
1
>>> aplusb(97,-99)
-2
>>> aplusb(1000,-500)
500
>>> aplusb(-1000,8000)
7000
1ビットの2進数学演算(^)が禁止されている場合は、単項演算を実行してください。
from itertools import chain
def unary(x):
"Unary representation of x"
return ''.join(['x' for _ in range(0,x)])
def uplus(x, y):
"Unary sum of x and y"
return [c for c in chain(x,y)]
def plus(i, j):
"Return sum calculated using unary math"
return len(uplus(unary(i), unary(j)))
これは、pythonは通常32ビットのsignedintを使用していないためです。
参照: ctypes.c_int32
受け入れられた解決策:
class Solution:
"""
@param a: The first integer
@param b: The second integer
@return: The sum of a and b
"""
def aplusb(self, a, b):
import ctypes
a = ctypes.c_int32(a).value
a = ctypes.c_int32(a).value
while b != 0:
carry = ctypes.c_int32(a & b).value
a = ctypes.c_int32(a ^ b).value
b = ctypes.c_int32(carry << 1).value
return a
私の解決策:
def foo(a, b):
"""iterate through a and b, count iteration via a list, check len"""
x = []
for i in range(a):
x.append(a)
for i in range(b):
x.append(b)
print len(x)
すでに述べたように、ビット単位の方が優れています。