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
52 changes: 52 additions & 0 deletions 0190.Reverse-Bits/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 190. Reverse Bits

## step1
strに直してreverseする。f-stringのフォーマットが分からず、調べた。

https://docs.python.org/ja/3/tutorial/inputoutput.html#formatted-string-literals
https://docs.python.org/ja/3/library/string.html#formatspec

bが2進数、x (Xで大文字)で16進数、#を付けるとプレフィックスが付く

0(桁数)で0埋め。他を書くときには><^などを書く

```python
>>> num = 42
>>> print(f"{num:b}")
101010
>>> print(f"{num:x}")
2a
>>> print(f"{num:#x}")
0x2a
>>> print(f"{num:#X}")
0X2A
>>> print(f"{num:03b}")
101010
>>> print(f"{num:03x}")
02a
>>> print(f"{num:-3x}")
2a
>>> print(f"{num:,3x}")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Invalid format specifier ',3x' for object of type 'int'
>>> print(f"{num:,>3x}")
,2a
>>> print(f"{num:,^6x}")
,,2a,,
```

bit演算でも書く。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

分割統治法で解く方法もあります。興味があれば探してみて下さい。ソフトウェアエンジニアの常識には含まれていないと思いますが、「ハッカーのたのしみ」に書かれており、これを読んだソフトウェアエンジニアなら知っていると思います。
https://www.amazon.co.jp/%E3%83%8F%E3%83%83%E3%82%AB%E3%83%BC%E3%81%AE%E3%81%9F%E3%81%AE%E3%81%97%E3%81%BF%E2%80%95%E6%9C%AC%E7%89%A9%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%81%AF%E3%81%84%E3%81%8B%E3%81%AB%E3%81%97%E3%81%A6%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%E3%81%8B-%E3%82%B8%E3%83%A5%E3%83%8B%E3%82%A2-%E3%83%98%E3%83%B3%E3%83%AA%E3%83%BC%E3%83%BBS-%E3%82%A6%E3%82%A9%E3%83%BC%E3%83%AC%E3%83%B3/dp/4434046683

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(pushするのを忘れていました。)
この解法は自分では全く思いつきませんでした。「ハッカーのたのしみ」はビット演算について詳しく書かれた本のようですね。機会があれば手に取ってみようと思います。


## step2
https://github.com/Kitaken0107/GrindEasy/pull/23

> 文字列に変換しないでやってみてください。ビット操作の問題だと思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ループで回してもいいですが、ビットマスクで隣同士のビットを入れ替えられますね。2ビットずつも入れ替えられますね。
また __builtin_bitreverse32 が環境によってはあります。
8ビットのルックアップテーブルを用意して4回使う手もあるかもしれません。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ルックアップテーブルは、昔はよく見たテクニックですが CPU が速くなってあまり見なくなりましたね。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

昔と比べて1000倍ほど速くなっているようですね。今のCPUのクロック数が3~6Ghzあたりというのは覚えておこうと思います。
https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures


> 32 bit 整数って、シフト演算をして、最下位ビットを見ると、スタックみたいなものじゃないですか。

---
以下を追加
- builtin (c++)
- divide and conquer
- 配列を前計算しておく
5 changes: 5 additions & 0 deletions 0190.Reverse-Bits/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Solution:
def reverseBits(self, n: int) -> int:
bit_expression = f"{n:032b}"
return int(bit_expression[::-1], 2)

12 changes: 12 additions & 0 deletions 0190.Reverse-Bits/step1_bit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Solution:
def reverseBits(self, n: int) -> int:
reversed_bits = 0
num_bits = 0
while num_bits < 32:
reversed_bits <<= 1
reversed_bits |= n & 1
n >>= 1
num_bits += 1
return reversed_bits


8 changes: 8 additions & 0 deletions 0190.Reverse-Bits/step2_builtin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <cstdint>

class Solution {
public:
uint32_t reverseBits(uint32_t n) {
return __builtin_bitreverse32(n);
}
};
10 changes: 10 additions & 0 deletions 0190.Reverse-Bits/step2_divide_and_conquer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Solution:
def reverseBits(self, n: int) -> int:
n = n & 0xffffffff
n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1)
n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2)
n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4)
n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8)
n = ((n & 0x0000ffff) << 16) | ((n & 0xffff0000) >> 16)

return n & 0xffffffff
21 changes: 21 additions & 0 deletions 0190.Reverse-Bits/step2_memory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Solution:
REVERSE_TABLE = [0] * 256

@classmethod
def init_table(cls):
for i in range(1, 256):
cls.REVERSE_TABLE[i] = (cls.REVERSE_TABLE[i >> 1] >> 1) | ((i & 1) << 7)

def __init__(self):
if self.REVERSE_TABLE[1] == 0:
self.init_table()

def reverseBits(self, n: int) -> int:
n = n & 0xffffffff

byte0 = self.REVERSE_TABLE[n & 0xff]
byte1 = self.REVERSE_TABLE[(n >> 8) & 0xff]
byte2 = self.REVERSE_TABLE[(n >> 16) & 0xff]
byte3 = self.REVERSE_TABLE[(n >> 24) & 0xff]

return (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3