Skip to content
Open
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
99 changes: 99 additions & 0 deletions 779. K-th Symbol in Grammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
### Step1

- まずは試しに全探索。これはまあダメ、TLEですね。予想通り。
- よく考えたら文字列で集計せずに、最初からintにしてもよかった

```python
class Solution:
def kthGrammar(self, n: int, k: int) -> int:
result = '0'
replaced_chars = []
for _ in range(n - 1):
for c in result:
if c == '0':
replaced_chars.append('01')
else:
replaced_chars.append('10')
result = "".join(replaced_chars)
replaced_chars = []
return int(result[k - 1])
```

- 2進法ぽい
- 14番目は前の7番目から発生したもので、その中の2個目なので7番目の反転で〜と考えると
- 0-indexにすれば13番目→1101、は前の6番目→110(1101の右シフト1回)から出るけどラスト1なのでそれを反転する、みたいに考えれば、2進法のbit分だけ反転する。0番目の時は0なのでbitcountが奇数か判定すればOK
- 中学受験の算数ぽい(好きではある)

```python

class Solution:
def kthGrammar(self, n: int, k: int) -> int:
return (k - 1).bit_count() % 2
```


## Step2

- 再帰という手もあったか、思いつかなかった(というか発想がいきなり2進法にいった)
- k_prevとか設けずいきなり引数に突っ込んでもよかった

```python

class Solution:
def kthGrammar(self, n: int, k: int) -> int:
if n == 1:
return 0
is_odd_index = k % 2
k_prev = (k + 1) // 2
if is_odd_index:
return self.kthGrammar(n - 1, k_prev)
else:
return 1 - self.kthGrammar(n - 1, k_prev)
```

- bitcountについての資料を読む

https://stackoverflow.com/questions/109023/count-the-number-of-set-bits-in-a-32-bit-integer

- x86というプロセッサなら命令がそのままあるらしい
- それ使わないやつが非常に面白い。(偶数bit + 奇数bit)によって先頭から2桁ずつbitcountして結果を2桁ずつに収める、先頭から4桁ずつbitcountして結果を4桁ずつに収める、を順に行う(説明が下手)
Copy link

Choose a reason for hiding this comment

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

https://www.oreilly.co.jp//books/9784873112886/mobile.html
「Binary Hacks ─ ハッカー秘伝のテクニック100選」薦めておきます。

Copy link

Choose a reason for hiding this comment

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

Choose a reason for hiding this comment

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

Copy link

Choose a reason for hiding this comment

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

そうでした。すみません、混ざってました。

Copy link
Owner Author

Choose a reason for hiding this comment

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

どちらも面白そうですね、ありがとうございます

- [CPythonのコード](https://github.com/python/cpython/blob/main/Include/internal/pycore_bitutils.h#L95)の該当箇所も発見。#if (defined(**clang**) || defined(**GNUC**))であるならbuitinのpopcountを使ってx86のプロセッサの命令を使用。そうでなければ、上記のアルゴリズムでやってる(最後だけ掛け算使ってる?実質同じ操作だけど)
- Cのlongに収まらない場合は[これ](https://github.com/python/cpython/blob/main/Objects/longobject.c#L6266C1-L6266C19)がCPython実装?多倍長はstructの中の配列にn進法の各桁(nはoverflowしない範囲)が入っているので、単純に各要素で上記の関数を実行して足している
- 他参考資料

https://github.com/hayashi-ay/leetcode/pull/46

- [0, 1][1, 0]への辞書として持つ選択肢もあり
- https://github.com/goto-untrapped/Arai60/pull/26/files
- https://github.com/Exzrgs/LeetCode/pull/12/files
- kのbitcountをあえてiterativeに実装(right to leftでやってみた)

```python

class Solution:
def kthGrammar(self, n: int, k: int) -> int:
k -= 1
result_digit = 0
while k:
if k & 1:
result_digit ^= 1
k >>= 1
return result_digit
```

- 前半一緒なのと、それに対する反転とみて再帰
- これなんでそうなるか考えたけど意外とむずい

## Step3

```python

class Solution:
def kthGrammar(self, n: int, k: int) -> int:
if n == 1:
return 0
if k % 2 == 0:
return 1 - self.kthGrammar(n - 1, (k + 1) // 2)
else:
return self.kthGrammar(n - 1, (k + 1) // 2)
```