From f59e4297ed85696fd7210b424096115766c3e307 Mon Sep 17 00:00:00 2001 From: mike <59136831+Mike0121@users.noreply.github.com> Date: Sat, 22 Jun 2024 19:28:01 +0900 Subject: [PATCH] Create 387. First Unique Character in a String.md https://leetcode.com/problems/first-unique-character-in-a-string/description/ --- ...87. First Unique Character in a String.md" | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 "\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/387. First Unique Character in a String.md" diff --git "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/387. First Unique Character in a String.md" "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/387. First Unique Character in a String.md" new file mode 100644 index 0000000..9c75d49 --- /dev/null +++ "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/387. First Unique Character in a String.md" @@ -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)
+空間計算量: O(N)
+ +### 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)
+空間計算量: O(N)
+ +```python +class Solution: + def firstUniqChar(self, s: str) -> int: + char_histogram = [0] * (ord('z') - ord('a') + 1) + for c in s: + char_histogram[ord(c) - ord('a')] += 1 + + 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に格納された値を操作している点が少し気になった。 + +時間計算量: O(N)
+空間計算量: O(N)
+ +```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)
+空間計算量: O(1)
+```python +class Solution: + def firstUniqChar(self, s: str) -> int: + for c in s: + if s.rindex(c) == s.index(c): + return s.index(c) + return -1 +``` + +## Counterを使った解法 +> https://docs.python.org/3/library/collections.html#collections.Counter +> カウンタオブジェクトは辞書のインターフェースを持ちますが、存在しない要素に対して KeyError を送出する代わりに 0 を返すという違いがあります +> defaultdict(int)と同じ。 +時間計算量: O(N)
+空間計算量: O(N)
+ +```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 +```