diff --git a/30-240604/main.py b/30-240604/main.py
new file mode 100644
index 0000000..967f266
--- /dev/null
+++ b/30-240604/main.py
@@ -0,0 +1,146 @@
+class TrieNode:
+    def __init__(self, val = ''):
+        self.child = []
+        self.is_word = 0
+        self.val = val
+        self.t = 1
+        self.child_map = {}
+class Trie:
+    def __init__(self):
+        self.root = TrieNode()
+        self.cnt = 0
+
+    def insert(self, word: str) -> None:
+        parent_node = self.root
+        for idx, letter in enumerate(word):
+            if letter not in parent_node.child_map:
+                new_node = TrieNode(letter)
+                parent_node.child.append(new_node)
+                parent_node.child_map[letter] = len(parent_node.child) - 1
+                parent_node = new_node
+            else:
+                idx = parent_node.child_map[letter]
+                parent_node = parent_node.child[idx]
+        if parent_node.is_word != 0:
+            parent_node.t += 1
+        parent_node.is_word = self.cnt + 1
+        self.cnt += 1
+
+    def search(self, word: str) :
+        parent_node = self.root
+        for idx, letter in enumerate(word):
+            if letter not in parent_node.child_map:
+                return None
+            idx = parent_node.child_map[letter]
+            parent_node = parent_node.child[idx]
+        if parent_node.is_word != 0:
+            return parent_node
+        return None
+
+    def startsWith(self, prefix: str) -> bool:
+        parent_node = self.root
+        for idx, letter in enumerate(prefix):
+            if letter not in parent_node.child_map:
+                return False
+            idx = parent_node.child_map[letter]
+            parent_node = parent_node.child[idx]
+        return True
+
+class Solution:
+    def findSubstring(self, s: str, words: list[str]) -> list[int]:
+        len_word = len(words[0])
+        tree = Trie()
+        is_word = []
+
+        rlt = []
+        state = []
+        word_cnt = {}
+
+        if len_word > len(s): return []
+
+        for word in words:
+            tree.insert(word)
+            r = tree.search(word)
+            if r != None:
+                word_cnt[r.is_word] = r.t
+        # print(word_cnt)
+
+        for idx, ch in enumerate(s):
+            if idx + len_word > len(s): break
+            waiting = s[idx:idx+len_word]
+            r = tree.search(waiting)
+            if r != None:
+                is_word.append(r.is_word)
+            else:
+                is_word.append(0)
+        for i in range(len_word - 1) : is_word.append(0)
+        for i in range(len_word):
+            if is_word[i] != 0:
+                tmp_dic = {is_word[i]: [i]}
+                state.append((tmp_dic,i,i))
+            else:
+                state.append(({},i,i))
+        
+        if len(words) == 1 and words[0] == s:
+            return [0]
+        # is_word[idx] = value words index / 0 if it is not a word
+        # state[dic_idx][0]
+        for i in range(len(is_word[len_word:])):
+            idx = i + len_word
+            dic_idx = idx % len_word
+            # print(f"current index: {idx}, {idx % len_word}")
+            # print(f"current dic: {state[dic_idx]}")
+            # print(f"is_word[idx]: {is_word[idx]}")
+            if is_word[idx] in state[dic_idx][0] and len(state[dic_idx][0][is_word[idx]]) >= word_cnt[is_word[idx]]:
+                # print("condition 1")
+                tmp = state[dic_idx][0][is_word[idx]][0]
+                tmp_l = []
+                for key in state[dic_idx][0]:
+                    for i, v in enumerate(state[dic_idx][0][key]):
+                        if v <= tmp:
+                            tmp_l.append((key, i))
+
+                for (key, i) in tmp_l:
+                    state[dic_idx][0][key].pop(i)
+                    if len(state[dic_idx][0][key]) == 0:
+                        del state[dic_idx][0][key]
+                
+                if is_word[idx] not in state[dic_idx][0]:
+                    state[dic_idx][0][is_word[idx]] = [idx] 
+                else:
+                    state[dic_idx][0][is_word[idx]].append(idx)
+                state[dic_idx] = (state[dic_idx][0], tmp + len_word, state[dic_idx][2])
+            elif is_word[idx] != 0:
+                # print("condition 2")
+                if len(state[dic_idx][0]) == 0:
+                    state[dic_idx] = ({}, idx, idx)
+                if is_word[idx] in state[dic_idx][0]:
+                    state[dic_idx][0][is_word[idx]].append(idx)
+                else:
+                    state[dic_idx][0][is_word[idx]]=[idx]
+            elif is_word[idx] == 0:
+                # print("condition 3")
+                state[dic_idx] = ({}, idx, idx)
+
+            state[dic_idx] = (state[dic_idx][0],state[dic_idx][1], idx)
+            s = 0
+            for k in state[dic_idx][0]:
+                s += len(state[dic_idx][0][k])
+            # if len(state[dic_idx][0]) == len(words):
+            if s == len(words):
+                # print(f"win, {idx}")
+                rlt.append(state[dic_idx][1])
+                del state[dic_idx][0][is_word[state[dic_idx][1]]]
+                state[dic_idx] = (state[dic_idx][0], state[dic_idx][1] + len_word, state[dic_idx][2])
+            # print(f"after fixed: {state[dic_idx]}")
+            # print()
+        return rlt
+
+sol = Solution()
+print(sol.findSubstring("barfoothefoobarman", words=["foo", "bar"]))
+print(sol.findSubstring("barfoofoobarthefoobarman", words=["foo", "bar", "the"]))
+print(sol.findSubstring("barbarbbar", words=["arb", "bar"]))
+print(sol.findSubstring("wordgoodgoodgoodbestword", words=["word", "good", "good", "best"]))
+print(sol.findSubstring("aaa", words=["a"]))
+print(sol.findSubstring("word", words=["word"]))
+