-
Notifications
You must be signed in to change notification settings - Fork 0
Create 387. First Unique Character in a String.md #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| > Note | ||
| > python dict型におけるpop, delの挙動に関して | ||
| > (TORUS0818さんのPR: https://github.com/TORUS0818/leetcode/pull/17) | ||
| ``` | ||
| https://docs.python.org/3/library/stdtypes.html#dict.pop | ||
| どちらも存在しない値を指定するとKeyError(ただ今回if文でチェックしているから今回は関係ない) | ||
| popは存在しない値だった場合、KeyErrorを出さずに第二引数で指定したdefault値を返せる e.g.) sample_dict.pop('b', 'default_value') | ||
| popは削除したkeyの値を返す、delは消すだけ | ||
| del文は複数削除可能 (これはlistのスライスに対してのコメントかも。) | ||
| そのほか、最後に追加されたkeyとvalueをどちらも返すmy_dict.popitem()、すべての要素を削除するdict.clear()がある。 | ||
| ``` | ||
|
|
||
| ```python | ||
| test_dict = {1: 1, 2: 4, 3: 9, 4: 16} | ||
|
|
||
| ## del O(1) | ||
| del test_dict[1] | ||
| print(test_dict) # {2: 4, 3: 9, 4: 16} | ||
|
|
||
| ## pop O(1) | ||
| val = test_dict.pop(4, "デフォルト") | ||
| print(val, test_dict) # 16 {2: 4, 3: 9} | ||
| val = test_dict.pop(4, "デフォルト") | ||
| print(val) # デフォルト | ||
|
|
||
| # popitem O(1) | ||
| key, val = test_dict.popitem() | ||
| print(key, val) # 3 9 | ||
|
|
||
| # clear O(N) | ||
| test_dict.clear() | ||
| print(test_dict) # {} | ||
| ``` | ||
|
|
||
|
|
||
| ## Dictによる解法 | ||
| 時間計算量: O(N)<br> | ||
| 空間計算量: O(N)<br> | ||
|
|
||
| ### 1回目 (10m33s) | ||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| letter_frequency_counter = defaultdict(int) | ||
| for c in s: | ||
| letter_frequency_counter[c] += 1 | ||
|
|
||
| for i, c in enumerate(s): | ||
| if letter_frequency_counter[c] == 1: | ||
| return i | ||
| return -1 | ||
| ``` | ||
|
|
||
| ### 2回目 | ||
| > letter_frequency_counterが少し冗長なため、char_counterに変更。 | ||
| > defaultdictではなく、dictを利用して、char_counter[c] = char_counter.get(c, 0) + 1でも良いかも。 | ||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| char_counter = defaultdict(int) | ||
| for c in s: | ||
| char_counter[c] += 1 | ||
|
|
||
| for i, c in enumerate(s): | ||
| if char_counter[c] == 1: | ||
| return i | ||
| return -1 | ||
| ``` | ||
|
|
||
| ### 3回目 | ||
| > 2回目から変更なし。 | ||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| char_counter = defaultdict(int) | ||
| for c in s: | ||
| char_counter[c] += 1 | ||
|
|
||
| for i, c in enumerate(s): | ||
| if char_counter[c] == 1: | ||
| return i | ||
| return -1 | ||
| ``` | ||
|
|
||
|
|
||
| ## ヒストグラム化を利用した解法 | ||
|
|
||
| 時間計算量: O(N)<br> | ||
| 空間計算量: O(N)<br> | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| char_histogram = [0] * (ord('z') - ord('a') + 1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oda さんか誰かが、英語圏の人が同僚になる想定で面接を受けましょうと言っていた気がします。英語圏の人にとってアルファベットが26文字なのは自明のはずなので、単に26を渡して配列を宣言してもいいのかなと思いました。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. すいません、投稿後すぐ考え直したのですが、翻って自分がひらがなの数をすぐ答えられるかと問われたら全然自信が無いなと思ったので、やはりこれで良いかも知れません...🫠
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. コメント有難うございます。そもそもちょっと練習のためにこの書き方を採用したというのが一番大きな理由になってしまうんですが、ALPHABET_NUMBER = 26が一番自分もわかりやすいですし、メンテナンスしやすいですね。 |
||
| for c in s: | ||
| char_histogram[ord(c) - ord('a')] += 1 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Mike0121 言語にもよりますが、リストへのindexアクセスは容易にクラッシュを引き起こすので気になりました。(確かPythonは負のindexを使えるんでしたっけ?) もし考慮済みだったら一言コメントがあるといいかもしれません |
||
|
|
||
| for i, c in enumerate(s): | ||
| if char_histogram[ord(c) - ord('a')] == 1: | ||
| return i | ||
|
|
||
| return -1 | ||
| ``` | ||
|
|
||
|
|
||
| ## 1-passの解法 | ||
| > for文自体は確かに1-passであるが、return char_to_index.values()で | ||
| > 結局はchar_to_indexに格納された値を操作している点が少し気になった。 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. あと min() が O(n) の操作をしているのも気になりますね... |
||
|
|
||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こちら下記でOdaさんが既に指摘済みでした。 |
||
| 時間計算量: O(N)<br> | ||
| 空間計算量: O(N)<br> | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| non_unique_chars = set() | ||
| char_to_index = {} | ||
|
|
||
| for i, c in enumerate(s): | ||
| if c in non_unique_chars: | ||
| continue | ||
|
|
||
| if c in char_to_index: | ||
| del char_to_index[c] | ||
| non_unique_chars.add(c) | ||
| continue | ||
| char_to_index[c] = i | ||
| if not char_to_index: | ||
| return -1 | ||
|
|
||
| return min(char_to_index.values()) | ||
| ``` | ||
|
|
||
| ## rindex, indexを利用した解法 | ||
| https://docs.python.org/3/library/stdtypes.html#str.index | ||
| https://docs.python.org/3/library/stdtypes.html#str.index | ||
|
|
||
| 時間計算量: O(N^2)<br> | ||
| 空間計算量: O(1)<br> | ||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| for c in s: | ||
| if s.rindex(c) == s.index(c): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. index は start の引数が使えるので、頭から尻尾まで見ない手もありますね。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Odaさん、ありがとうございます。 |
||
| return s.index(c) | ||
| return -1 | ||
| ``` | ||
|
|
||
| ## Counterを使った解法 | ||
| > https://docs.python.org/3/library/collections.html#collections.Counter | ||
| > カウンタオブジェクトは辞書のインターフェースを持ちますが、存在しない要素に対して KeyError を送出する代わりに 0 を返すという違いがあります | ||
| > defaultdict(int)と同じ。 | ||
| 時間計算量: O(N)<br> | ||
| 空間計算量: O(N)<br> | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| letter_frequency_counter = Counter(s) | ||
| for i, c in enumerate(s): | ||
| if letter_frequency_counter[c] == 1: | ||
| return i | ||
| return -1 | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
char_histogram は英小文字の差しか見れないと思うので、alphabet_histogram とかでもいいかもしれません。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Yoshiki-Iwasa さん、 @goto-untrapped さん レビューコメントありがとうございます。
問題文の制約で、lower case English lettersのためこの書き方にしていますが、それ以外の入力があった場合はエラー処理を書くか、コメントがあったほうが親切ですね。また、list範囲外のindexは、pythonでは
IndexError: list index out of rangeが発生します。負の値もindexに使えますが、末尾から値を取る形になります。(ちょっと公式ドキュメントが見当たりませんでした。https://qiita.com/mo256man/items/ed8ea21bd0ae94e5ed48)また、@goto-untrappedさんからコメントいただいた通り、変数名が良くない(広い)ので、alphabet_histogramの方が良いですね。