Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions 0191.Number-of-1-Bits/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# 191. Number of 1 Bits

## step1
1mもかからなかった。strでも書く。

## 他の人のコード
https://github.com/Ryotaro25/leetcode_first60/pull/76

> 整数の割り算は遅い、ビット演算は速い、という感覚は持っておいたほうが良いと思います
pythonだと差はなさそう

> 分割統治法による解法もあります。

この解法はおもしろい。有名な解法らしい。

足している数字はそれぞれ二進数で0101..., 00110011...,00001111...となっている。

一行目で2bitずつ区切った場所のbitカウントを2bitずつ2進数で表現し、二行目で4bit,..最終的に32bitのbitカウントになる。

> https://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation

1. 上の解法はtree patternと呼ばれている。
> For processors lacking those features, the best solutions known are based on adding counts in a tree pattern
> The above implementations have the best worst-case behavior of any known algorithm

2. 上の亜種がある。0x01010101をかける。筆算を考えるとわかりやすい。

以下でもいけるのではと思ったが、よく考えるとうまくいかない。4bitで、最大値を表現できないため

```python
class Solution:
def hammingWeight(self, n: int) -> int:
n = n & 0xffffffff
n = (n & 0x55555555) + ((n >> 1) & 0x55555555)
n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
return ((n * 0x11111111) & 0xffffffff) >> 28
```

3. &を取ると右端の1が消える。これも実装してみる。
> As Wegner described in 1960,[14] the bitwise AND of x with x − 1 differs from x only in zeroing out the least significant nonzero bit: subtracting 1 changes the rightmost string of 0s to 1s, and changes the rightmost 1 to a 0. If x originally had n bits that were 1, then after only n iterations of this operation, x will be reduced to zero. The following implementation is based on this principle.

4. 大きなメモリを使う解法


---

そもそも、builtinに専用の関数がある
https://docs.python.org/ja/3/library/stdtypes.html#int.bit_count



> https://github.com/rihib/leetcode/pull/46#pullrequestreview-2381278969

勉強になる。特に以下。
> ここで注目したいのは、 xとその2の補数はお互いにRightmost set bit以外が反転しているということである。つまり、x & -xとすると、Rightmost set bitのみが1になったビット列を得ることができる。よって、x - (x & -x)としてあげれば、 xのRightmost set bitをunsetすることができるのである。

> Rightmost unset bitをsetする方法
flippedで考えて最後にflippする

https://www.geeksforgeeks.org/dsa/set-rightmost-unset-bit/

8 changes: 8 additions & 0 deletions 0191.Number-of-1-Bits/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Solution:
def hammingWeight(self, n: int) -> int:
hamming_weight = 0
while n > 0:
hamming_weight += n & 1
n >>= 1
return hamming_weight

4 changes: 4 additions & 0 deletions 0191.Number-of-1-Bits/step1_str.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Solution:
def hammingWeight(self, n: int) -> int:
return sum(int(bit) for bit in f"{n:b}")

3 changes: 3 additions & 0 deletions 0191.Number-of-1-Bits/step2_builtin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Solution:
def hammingWeight(self, n: int) -> int:
return n.bit_count()
7 changes: 7 additions & 0 deletions 0191.Number-of-1-Bits/step2_divide_and_conque_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Solution:
def hammingWeight(self, n: int) -> int:
n = (n & 0x55555555) + ((n >> 1) & 0x55555555)
n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
n = (n + (n >> 4)) & 0x0f0f0f0f

return (n * 0x01010101) >> 24
9 changes: 9 additions & 0 deletions 0191.Number-of-1-Bits/step2_divide_and_conquer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Solution:
def hammingWeight(self, n: int) -> int:
n = n & 0xffffffff
n = (n & 0x55555555) + ((n >> 1) & 0x55555555)
n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f)
n = (n & 0x00ff00ff) + ((n >> 8) & 0x00ff00ff)
n = (n & 0x0000ffff) + ((n >> 16) & 0x0000ffff)
return n
15 changes: 15 additions & 0 deletions 0191.Number-of-1-Bits/step2_lookup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Solution:
WORDBITS = [0] * 65536

@classmethod
def init_wordbits(cls):
for i in range(1, len(cls.WORDBITS)):
cls.WORDBITS[i] = cls.WORDBITS[i >> 1] + (i & 1)

def __init__(self):
if self.WORDBITS[1] == 0:
self.init_wordbits()

def hammingWeight(self, n: int) -> int:
n = n & 0xffffffff
return self.WORDBITS[n & 0xffff] + self.WORDBITS[n >> 16]
8 changes: 8 additions & 0 deletions 0191.Number-of-1-Bits/step2_wegner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Solution:
def hammingWeight(self, n: int) -> int:
hamming_weight = 0
while n > 0:
n &= n - 1
hamming_weight += 1
return hamming_weight