Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions 387/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 387. First Unique Character in a String

- 愚直な実装(sol1.py)は2回文字を見る
- https://discord.com/channels/1084280443945353267/1233603535862628432/1238208008182562927
- 文字が一回しか流れてこない場合を考えたい(sol2.py)
- Ordered dictを使うと書ける
- 速くなった

- Queueも使う実装もある
- https://github.com/colorbox/leetcode/pull/29/changes/BASE..48f2749be9c4ec78c6f24c887880e34c7206f678#r1861430039
- sol3.py
- queue.Queueにはpeek(先頭の覗き見)がない
- queueメソッドを使ったが推奨されないと思う
- dequeを使うのが良い気がする
- OrderedDictの実装はdoubly-linked list
- 実装した (sol4.py)
- 参考:https://gist.github.com/joequery/12332f410a05e6c7c949
- "Doubly"によって前の参照ができることにより、削除をO(1)で実行可能
- 「これ、OrderedDict の中身は Doubly-Linked List なので、まあ、練習としては、Doubly-Linked List 自体を書いて欲しいところではありますね。」
14 changes: 14 additions & 0 deletions 387/sol1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
START_CHAR = "a"
START_CHAR_ORD = ord(START_CHAR)
NUM_CHARS = 26


class Solution:
def firstUniqChar(self, s: str) -> int:
ord_to_count = [0] * NUM_CHARS
for c in s:
ord_to_count[ord(c) - START_CHAR_ORD] += 1
for i, c in enumerate(s):
if ord_to_count[ord(c) - START_CHAR_ORD] == 1:
return i
return -1
17 changes: 17 additions & 0 deletions 387/sol2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from collections import OrderedDict


class Solution:
def firstUniqChar(self, s: str) -> int:
seen_chars = set()
char_to_idx = OrderedDict()
for i, c in enumerate(s):
if c in seen_chars:
if c in char_to_idx:
del char_to_idx[c]
continue
seen_chars.add(c)
char_to_idx[c] = i
if char_to_idx:
return next(iter(char_to_idx.values()))
return -1
22 changes: 22 additions & 0 deletions 387/sol3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import queue


class Solution:
def firstUniqChar(self, s: str) -> int:
import queue
from collections import defaultdict

counts = defaultdict(int)
count_and_idxs = queue.Queue()

for i, c in enumerate(s):
counts[c] += 1
count_and_idxs.put((c, i))

while not count_and_idxs.empty():
front_c, _front_i = count_and_idxs.queue[0]
if counts[front_c] == 1:
break
count_and_idxs.get()

return count_and_idxs.queue[0][1] if not count_and_idxs.empty() else -1
52 changes: 52 additions & 0 deletions 387/sol4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class Link:
def __init__(self, prev=None, next=None, key=None):
self.prev = prev
self.next = next
self.key = key


class CustomOrderedDict(dict):
def __init__(self):
super().__init__()
self.root = Link()
self.root.prev = self.root.next = self.root
self.link_map = {}

def __getitem__(self, key):
return super().__getitem__(key)

def __setitem__(self, key, value):
if key not in self:
last = self.root.prev
new_link = Link(prev=last, next=self.root, key=key)
last.next = self.root.prev = new_link
self.link_map[key] = new_link
super().__setitem__(key, value)

def __delitem__(self, key):
super().__delitem__(key)
link = self.link_map.pop(key)
link.prev.next = link.next
link.next.prev = link.prev

def __iter__(self):
curr = self.root.next
while curr is not self.root:
yield curr.key
curr = curr.next


class Solution:
def firstUniqChar(self, s: str) -> int:
seen_chars = set()
char_to_idx = CustomOrderedDict()
for i, c in enumerate(s):
if c in seen_chars:
if c in char_to_idx:
del char_to_idx[c]
continue
seen_chars.add(c)
char_to_idx[c] = i
if char_to_idx:
return next(iter(char_to_idx.values()))
return -1