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
+```