-
Notifications
You must be signed in to change notification settings - Fork 0
387. First Unique Character in a String #3
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
base: main
Are you sure you want to change the base?
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,69 @@ | ||
| # 387. First Unique Character in a String | ||
|
|
||
| ## Step 1 | ||
| - 一回文字列を頭から舐めて文字:出現数で辞書に登録 | ||
| - もう一度文字列を走査して、出現数が1の文字のインデックス(かなければ-1)を返す | ||
| - 時間、空間ともにO(n) | ||
| - 入力が<= 10^5であることを考えるとPythonでも0.1秒収まるくらい?(平均的な処理能力を10^8/sec、Pythonがそこから最悪100倍で見積もっています、初めてなので勘違いしている点やリファレンスがあればコメントください) | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| appearences: dict[str, int] = {} | ||
|
|
||
| for c in s: | ||
| if c in appearences: | ||
| appearences[c] += 1 | ||
| else: | ||
| appearences[c] = 1 | ||
|
|
||
| for c in s: | ||
| if appearences[c] == 1: | ||
| return s.index(c) | ||
|
|
||
| return -1 | ||
| ``` | ||
|
|
||
| ## Step 2 | ||
| - enumerate()を使っている人が多かった。str.index()は文字列を走査し直す(当然でした)のでここで最悪O(n^2)になっている。 | ||
| - collections.Counter()という便利なやつがいる。 | ||
| ```python | ||
| from collections import Counter | ||
|
|
||
|
|
||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| appearences = Counter(s) | ||
|
|
||
| for i, c in enumerate(s): | ||
| if appearences[c] == 1: | ||
| return i | ||
|
|
||
| return -1 | ||
| ``` | ||
|
|
||
| - OrderDictという要素の順番を保持してくれるものがある。辞書の値に出現回数ではなく最初に見つけたインデックスを保存し、二回目以降の出現があればそれを潰しておく。二回目のループのとき、辞書は文字列に登場した順番通りになっているので、潰れていないインデックスが出た瞬間それを返して問題ない。 | ||
| - Python3.7以降ふつうのdictも追加順を保持しているらしく(Dictionaries preserve insertion order.(https://docs.python.org/3/library/stdtypes.html#mapping-types-dict))、そのままdictで実装した。OrderDictをインポートしたほうがいいんでしょうか? | ||
| - 2回目のループが最長26回で済むのでだいぶ効率的。 | ||
|
|
||
| ```python | ||
| class Solution2: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| seen_index:dict[str, int] = {} | ||
|
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. コロンと型名の間には空白を入れるのが一般的だと思います。 seen_index: dict[str, int] = {} |
||
| duplicated = -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. Pythonでも、他の言語と同様定数は大文字で記載するのが一般的です。
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. 失念しておりました、ありがとうございます。 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. Google C++ Style Guide では、定数は kConstantValue の形で記載することになっています。 https://google.github.io/styleguide/cppguide.html#Constant_Names
ただ、この命名規約は、かなりマイナーだともいます。 |
||
|
|
||
| for i, c in enumerate(s): | ||
| if c in seen_index: | ||
| seen_index[c] = duplicated | ||
| else: | ||
| seen_index[c] = i | ||
|
|
||
| for idx in seen_index.values(): | ||
| if idx != duplicated: | ||
| return idx | ||
|
|
||
| return -1 | ||
| ``` | ||
|
|
||
| ## Step 3 | ||
| - OrderDictのほうが効率的かつ明示的だと思ったのでそちらで三回実装。 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| appearences: dict[str, int] = {} | ||
|
|
||
| for c in s: | ||
| if c in appearences: | ||
| appearences[c] += 1 | ||
| else: | ||
| appearences[c] = 1 | ||
|
|
||
| for c in s: | ||
| if appearences[c] == 1: | ||
| return s.index(c) | ||
|
|
||
| return -1 | ||
|
|
||
|
|
||
| def main() -> None: | ||
| Solver = Solution() | ||
| s = "loveleetcode" | ||
| res = Solver.firstUniqChar(s) | ||
| print(res) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| from collections import Counter | ||
|
|
||
|
|
||
| class Solution: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| appearences = Counter(s) | ||
|
|
||
| for i, c in enumerate(s): | ||
| if appearences[c] == 1: | ||
| return i | ||
|
|
||
| return -1 | ||
|
|
||
|
|
||
| class Solution2: | ||
| def firstUniqChar(self, s: str) -> int: | ||
| seen_index:dict[str, int] = {} | ||
| duplicated = -1 | ||
|
|
||
| for i, c in enumerate(s): | ||
| if c in seen_index: | ||
| seen_index[c] = duplicated | ||
| else: | ||
| seen_index[c] = i | ||
|
|
||
| for idx in seen_index.values(): | ||
| if idx != duplicated: | ||
| return idx | ||
|
|
||
| return -1 |
Uh oh!
There was an error while loading. Please reload this page.
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.
実行時間については、以下が参照されることが多いです。
Yuto729/leetcode#16 (comment)
数字については、根拠を大事にするとよいと思います。
(「平均的な処理能力を10^8/sec、Pythonがそこから最悪100倍」という部分ですね)
上記のURLでも、CPUの周波数、IPC、スレッド数など、いくつかの仮定を置いています。
また、「最悪100倍」、という見積もりの根拠として、上記のURLでは言語ごとの処理速度が紹介されていますが、その結果を自分自身がどのように利用しているのかは、意識しておく必要があると思います。
例えば、同じ「PythonはC++と比べて100倍遅い」という結果を利用する場合でも、根拠は様々です。
・言語ごとの処理速度をみると、「PythonはC++と比べて100倍くらい遅い」ことが分かる。多くの人が参照しているため、この結果を利用することにした。
・言語ごとの処理速度を確認したところ、READMEに測定条件(Rules)が記載されており、自分が想定する計算環境と大きく乖離していない。そこで、「PythonはC++と比べて100倍遅い」という結果を利用することにした。ただし、ソースコードは確認していない。
・実際にソースコードを確認した結果、測定条件や比較方法が妥当であることを確認できたため、そこから得られる「PythonはC++と比べて100倍遅い」という結果を利用することにした。
・実際に自分自身で同じ条件を再現して測定したところ、実際にC++とPythonは100倍程度の差が確認できたため、この結果を利用することにした。
自分がなぜそう結論付けたのか、説明できることが重要だと思います。
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.
ご丁寧にありがとうございます。
一旦は、
このスタンス(根拠)とし、追ってソースコードの確認や自分での再現を行い、計算量に関する感覚や説明を磨いていこうと思います。
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.
原理が重要な時もありまして、例えば、組み込み関数を呼んだ中が律速のときは、100倍にならないです。個人的には文字列操作は1倍、整数操作は20倍くらいで考えてます。