diff --git a/387. First Unique Character in a String.md b/387. First Unique Character in a String.md new file mode 100644 index 0000000..7d0d968 --- /dev/null +++ b/387. First Unique Character in a String.md @@ -0,0 +1,107 @@ +愚直にやるなら前から1文字ずつ見ていってそれぞれ重複がないかを調べる。計算量は $O(n^2)$ で問題の設定上nは最大10^5になるので10^10になりTLEしそうなので別の解法を考える必要がある。 +あらかじめユニークな文字を求めたあとで前から見ていけば $O(n)$ でいける。ユニークを求める方法は、各文字の登場回数をカウンティングしたりする感じで良さそう。 +ただ上記の方法では2周する必要がある。後ろから見ていって、最後に初めて登場した文字を覚えていれば1回文字列を後ろからなめるだけで解けそう。← と思ったけどそんなことはなくて結構大変そう。 + + +1st + +文字の登場回数をあらかじめカウントする。 +英アルファベット小文字をインデックス値に変換する処理は関数に切り出しても良いがtoo muchか。 + +```python +class Solution: + def firstUniqChar(self, s: str) -> int: + freq = [0] * 26 + for c in s: + freq[ord(c) - ord('a')] += 1 + for i, c in enumerate(s): + if freq[ord(c) - ord('a')] == 1: + return i + return -1 +``` + +2nd + +1stでは課題の制約で英アルファベット小文字のみだったので配列で管理したがdictを使う版でも解いた。Counterを使っても良い。 + +```python +class Solution: + def firstUniqChar(self, s: str) -> int: + freq = defaultdict(int) + for c in s: + freq[c] += 1 + for i, c in enumerate(s): + if freq[c] == 1: + return i + return -1 +``` + +Counterを使った版 + +```python +class Solution: + def firstUniqChar(self, s: str) -> int: + freq = Counter(s) + for i, c in enumerate(s): + if freq[c] == 1: + return i + return -1 +``` + +3rd + +1stと同じ。 + +```python +class Solution: + def firstUniqChar(self, s: str) -> int: + freq = [0] * 26 + for c in s: + freq[ord(c) - ord('a')] += 1 + for i, c in enumerate(s): + if freq[ord(c) - ord('a')] == 1: + return i + return -1 +``` + +4th + +1から3と違いsを1回だけなめる。登場したindexの位置と2回以上登場したかどうかは別に管理しても良いが一旦infが2回以上登場したと扱って1つで管理するようにした。 +minを使っている部分は、Python3.7からdictへの追加順が仕様として保証されるようになったので他に書きようがある。 +1から3だと`aaaaaaaaaa ... b`みたいな文字だと2周する必要があったのでこちらの方が1周で済む分良い。 + +```python +class Solution: + def firstUniqChar(self, s: str) -> int: + char_to_first_appear_index = {} + for index, c in enumerate(s): + if c in char_to_first_appear_index: + char_to_first_appear_index[c] = inf + else: + char_to_first_appear_index[c] = index + min_index = min(char_to_first_appear_index.values()) + if min_index == inf: + return -1 + return min_index +``` + +4-1をベースに書き直し。登場したindexの位置と重複しているかを別で管理するように。Pythonのdictの追加順が保存されていることを利用するように。 +https://docs.python.org/3/library/stdtypes.html#dictionary-view-objects + +```python +class Solution: + def firstUniqChar(self, s: str) -> int: + char_to_first_appear_index = {} + duplicated = set() + for index, c in enumerate(s): + if c in duplicated: + continue + if c in char_to_first_appear_index: + del char_to_first_appear_index[c] + duplicated.add(c) + continue + char_to_first_appear_index[c] = index + if not char_to_first_appear_index: + return -1 + return next(iter(char_to_first_appear_index.values())) +``` diff --git a/java.md b/java.md new file mode 100644 index 0000000..445fa11 --- /dev/null +++ b/java.md @@ -0,0 +1,20 @@ +1st + +```java +class Solution { + public int firstUniqChar(String s) { + HashMap charToFreq = new HashMap<>(); + + for (char c: s.toCharArray()) { + int prevFreq = charToFreq.getOrDefault(c, 0); + charToFreq.put(c, prevFreq + 1); + } + for (int i = 0; i < s.length(); i++) { + if (charToFreq.get(s.charAt(i)) == 1) { + return i; + } + } + return -1; + } +} +```