Skip to content
Merged
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
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,8 @@
* [Test Greatest Common Divisor](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/greatest_common_divisor/test_greatest_common_divisor.py)
* Inttostr
* [Test Int To Str](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/inttostr/test_int_to_str.py)
* Is Prefix
* [Test Is Prefix Of Word](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/is_prefix/test_is_prefix_of_word.py)
* Is Unique
* [Test Is Unique](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/is_unique/test_is_unique.py)
* Issubsequence
Expand Down
28 changes: 14 additions & 14 deletions algorithms/fast_and_slow/happy_number/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ Return TRUE if n is a happy number, and FALSE if not.

### Sample Example 1

![Sample Example 1.1](example_1_1.png)
![Sample Example 1.2](example_1_2.png)
![Sample Example 1.3](example_1_3.png)
![Sample Example 1.1](images/example/example_1_1.png)
![Sample Example 1.2](images/example/example_1_2.png)
![Sample Example 1.3](images/example/example_1_3.png)

### Sample Example 2

![Sample Example 2.1](example_2_1.png)
![Sample Example 2.2](example_2_2.png)
![Sample Example 2.3](example_2_3.png)
![Sample Example 2.1](images/example/example_2_1.png)
![Sample Example 2.2](images/example/example_2_2.png)
![Sample Example 2.3](images/example/example_2_3.png)

## Solution Example

Below shows an example using Floyd's Cycle Detection Algorithm or Tortoise and Hare algorithm to detect a cycle
for the number 2.

![Solution Example 1](solution_example_1.png)
![Solution Example 2](solution_example_2.png)
![Solution Example 3](solution_example_3.png)
![Solution Example 4](solution_example_4.png)
![Solution Example 5](solution_example_5.png)
![Solution Example 6](solution_example_6.png)
![Solution Example 7](solution_example_7.png)
![Solution Example 8](solution_example_8.png)
![Solution Example 1](images/solution/solution_example_1.png)
![Solution Example 2](images/solution/solution_example_2.png)
![Solution Example 3](images/solution/solution_example_3.png)
![Solution Example 4](images/solution/solution_example_4.png)
![Solution Example 5](images/solution/solution_example_5.png)
![Solution Example 6](images/solution/solution_example_6.png)
![Solution Example 7](images/solution/solution_example_7.png)
![Solution Example 8](images/solution/solution_example_8.png)
6 changes: 6 additions & 0 deletions algorithms/fast_and_slow/happy_number/test_happy_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ def test_9(self):
actual = is_happy_number_2(number)
self.assertFalse(actual)

def test_10(self):
"""should return false for 20"""
number = 20
actual = is_happy_number_2(number)
self.assertFalse(actual)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion datastructures/streams/stream_checker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def query(self, letter: str) -> bool:

# Iterate stream in reverse (newest character first)
for character in reversed(self.stream):
# Check for dead end (critical for query logic)
# Check for dead-end (critical for query logic)
if character not in current.children:
return False

Expand Down
56 changes: 44 additions & 12 deletions datastructures/trees/trie/trie.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,59 @@
from typing import List
from typing import List, Optional
from datastructures.trees.trie.trie_node import TrieNode


class Trie:
def __init__(self):
self.root = TrieNode()

def insert(self, word: str) -> None:
def insert(self, word: str, index: Optional[int] = None) -> None:
"""
Inserts a word into the Trie. This has an optional index argument that allows
us to track the index of the word in the original list. So, if inserting words from a list such as "The author
is smart", the index of "smart" would be 3. If this is not provided, i.e. None, then each node in the tree will
have an index of None. Note that for each character in the word, we update the index of the node to the index of
the word. For example:

sentence = "please playground player"

Insert "please" (index 0):
p(0) → l(0) → e(0) → a(0) → s(0) → e(0)

Insert "playground" (index 1):
p(0) → l(0) → a(1) → y(1) → g(1) → ...
e(0) → a(0) → s(0) → e(0)

Insert "player" (index 2):
p(0) → l(0) → a(1) → y(1) → ...
e(2) → r(2)

Index then tracks the earliest index of the word in the original list. So, for the example above, the index of
"player" would be 2, not 0.

Parameters:
word (str): The word to insert
index (Optional[int]): The index of the word (default is None)

Returns:
None
"""
curr = self.root

for char in word:
if char in curr.children:
curr = curr.children[char]
else:
new_node = TrieNode()
curr.children[char] = new_node
curr = new_node
curr = curr.children[char]
if index is not None:
curr.index = min(curr.index or float("inf"), index)

curr.is_end = True

def search(self, word: str) -> List[str]:
curr = self.root

if len(word) == 0:
return []

curr = self.root

for char in word:
if char in curr.children:
curr = curr.children[char]
Expand All @@ -35,10 +64,10 @@ def search(self, word: str) -> List[str]:

def dfs(node: TrieNode, prefix: str) -> None:
if node.is_end:
output.append((prefix + node.char))
output.append((prefix + "".join(node.children.keys())))

for child in node.children.values():
dfs(child, prefix + node.char)
dfs(child, prefix + "".join(node.children.keys()))

dfs(curr, word[:-1])
return output
Expand All @@ -55,3 +84,6 @@ def starts_with(self, prefix: str) -> bool:
curr = curr.children[char]

return True

def __repr__(self):
return f"Trie(root={self.root})"
43 changes: 41 additions & 2 deletions datastructures/trees/trie/trie_node.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import DefaultDict
from typing import DefaultDict, Optional
from collections import defaultdict


Expand All @@ -18,6 +18,45 @@ def __init__(self):
"""
self.children: DefaultDict[str, TrieNode] = defaultdict(TrieNode)
self.is_end = False
self.index: Optional[int] = None

def __repr__(self):
return f"TrieNode({self.children.items()}, {self.is_end})"
return f"TrieNode(children={self.children.items()}, index={self.index}, is_end={self.is_end})"

def insert(self, word: str, index: int):
"""
Inserts a word into the TrieNode.

Parameters:
word (str): The word to insert
index (int): The index of the word

Returns:
None
"""
curr = self
for char in word:
curr = curr.children[char]
curr.index = min(curr.index or float("inf"), index)
curr.is_end = True

def search_prefix(self, prefix: str) -> int:
"""
Searches for a prefix in the TrieNode.

Parameters:
prefix (str): The prefix to search for

Returns:
int: The index of the word if the prefix is found, -1 otherwise
"""
current = self

for char in prefix:
if char not in current.children:
return -1

# Traverse to the next node
current = current.children[char]

return current.index if current.index is not None else -1
24 changes: 24 additions & 0 deletions pystrings/is_prefix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Check if a Word is a Prefix of Any Word in a Sentence

You are given a sentence containing words separated by single spaces and a searchWord. Your task is to determine whether
searchWord is a prefix of any word in the sentence.
Return the 1-based index of the first word in which searchWord appears as a prefix.

- If searchWord is a prefix of multiple words, return the index of the earliest such word.
- If no word starts with searchWord, return −1

> A prefix of a string is any contiguous substring that begins at the first character.

Constraints:

- 1 <= sentence.length <= 100
- 1 <= search_word.length <= 10
- The sentence consists of lowercase English letters and spaces.
- search_word consists of lowercase English letters.

## Examples

![Example 1](./images/examples/is_prefix_example_1.png)
![Example 2](./images/examples/is_prefix_example_2.png)
![Example 3](./images/examples/is_prefix_example_3.png)
![Example 4](./images/examples/is_prefix_example_4.png)
23 changes: 23 additions & 0 deletions pystrings/is_prefix/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from datastructures.trees.trie.trie_node import TrieNode


def is_prefix_of_word(sentence: str, search_word: str) -> int:
"""
This function will check if a given search_word is a prefix of any word in a sentence.

Parameters:
sentence (str): The sentence to search in.
search_word (str): The prefix to search for.

Returns:
int: The index of the word if the prefix is found, -1 otherwise.
"""
trie = TrieNode()
word_list = sentence.split(" ")

# Insert the words into the trie with their respective index
for index, word in enumerate(word_list, start=1):
trie.insert(word, index)

# Search for the prefix in the trie
return trie.search_prefix(search_word)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions pystrings/is_prefix/test_is_prefix_of_word.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import unittest
from . import is_prefix_of_word


class IsPrefixOfWordTestCase(unittest.TestCase):
def test_1(self):
sentence = "i love coding"
search_word = "lov"
expected = 2
actual = is_prefix_of_word(sentence, search_word)
self.assertEqual(expected, actual)

def test_2(self):
sentence = "hello world"
search_word = "he"
expected = 1
actual = is_prefix_of_word(sentence, search_word)
self.assertEqual(expected, actual)

def test_3(self):
sentence = "please playground player"
search_word = "pla"
expected = 2
actual = is_prefix_of_word(sentence, search_word)
self.assertEqual(expected, actual)

def test_4(self):
sentence = "open source ai"
search_word = "deep"
expected = -1
actual = is_prefix_of_word(sentence, search_word)
self.assertEqual(expected, actual)

def test_5(self):
sentence = "cats dog cattle category"
search_word = "cat"
expected = 1
actual = is_prefix_of_word(sentence, search_word)
self.assertEqual(expected, actual)

def test_6(self):
sentence = "this is fine"
search_word = "fi"
expected = 3
actual = is_prefix_of_word(sentence, search_word)
self.assertEqual(expected, actual)

def test_7(self):
sentence = "hello world"
search_word = "x"
expected = -1
actual = is_prefix_of_word(sentence, search_word)
self.assertEqual(expected, actual)


if __name__ == '__main__':
unittest.main()
Loading