Skip to content

Commit 3cc0667

Browse files
authored
Merge pull request #1565 from ivanpenaloza/march03
adding algo
2 parents 89e6227 + 5baee6e commit 3cc0667

5 files changed

Lines changed: 260 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from typing import List, Union, Collection, Mapping, Optional
2+
from abc import ABC, abstractmethod
3+
4+
class Solution:
5+
def twoSum(self, nums: List[int], target: int) -> List[int]:
6+
7+
answer = dict()
8+
9+
for k, v in enumerate(nums):
10+
11+
if v in answer:
12+
return [answer[v], k]
13+
else:
14+
answer[target - v] = k
15+
16+
return []
17+
18+
19+
20+
21+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import List, Union, Collection, Mapping, Optional
2+
from abc import ABC, abstractmethod
3+
import re
4+
5+
class Solution:
6+
def isPalindrome(self, s: str) -> bool:
7+
8+
# To lowercase
9+
s = s.lower()
10+
11+
# Remove non-alphanumeric characters
12+
s = re.sub(pattern=r'[^a-zA-Z0-9]', repl='', string=s)
13+
14+
# Determine if s is palindrome or not
15+
len_s = len(s)
16+
17+
for i in range(len_s//2):
18+
19+
if s[i] != s[len_s - 1 - i]:
20+
return False
21+
22+
return True
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from typing import List, Union, Collection, Mapping, Optional
2+
from abc import ABC, abstractmethod
3+
from collections import deque, defaultdict
4+
5+
class Solution:
6+
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
7+
"""
8+
Find the shortest transformation sequence from beginWord to endWord.
9+
Uses BFS to find the shortest path.
10+
11+
Time Complexity: O(M^2 * N) where M is word length, N is wordList size
12+
Space Complexity: O(M^2 * N) for the pattern dictionary
13+
"""
14+
# If beginWord equals endWord, the sequence is just the word itself
15+
if beginWord == endWord:
16+
return 1
17+
18+
# If endWord is not in wordList, no valid transformation exists
19+
if endWord not in wordList:
20+
return 0
21+
22+
# Convert wordList to set for O(1) lookup
23+
word_set = set(wordList)
24+
25+
# Build a pattern dictionary to find all words that differ by one letter
26+
# e.g., "hot" -> {"*ot": ["hot"], "h*t": ["hot"], "ho*": ["hot"]}
27+
pattern_dict = defaultdict(list)
28+
word_len = len(beginWord)
29+
30+
# Add beginWord to the set if not present
31+
if beginWord not in word_set:
32+
word_set.add(beginWord)
33+
34+
# Create patterns for all words
35+
for word in word_set:
36+
for i in range(word_len):
37+
pattern = word[:i] + '*' + word[i+1:]
38+
pattern_dict[pattern].append(word)
39+
40+
# BFS to find shortest path
41+
queue = deque([(beginWord, 1)]) # (current_word, level)
42+
visited = {beginWord}
43+
44+
while queue:
45+
current_word, level = queue.popleft()
46+
47+
# Try all possible transformations by replacing each character
48+
for i in range(word_len):
49+
pattern = current_word[:i] + '*' + current_word[i+1:]
50+
51+
# Get all words matching this pattern
52+
for next_word in pattern_dict[pattern]:
53+
if next_word == endWord:
54+
return level + 1
55+
56+
if next_word not in visited:
57+
visited.add(next_word)
58+
queue.append((next_word, level + 1))
59+
60+
# Clear the pattern to avoid revisiting in future iterations
61+
pattern_dict[pattern] = []
62+
63+
return 0
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
function ladderLength(beginWord: string, endWord: string, wordList: string[]): number {
2+
/**
3+
* Find the shortest transformation sequence from beginWord to endWord.
4+
* Uses BFS to find the shortest path.
5+
*
6+
* Time Complexity: O(M^2 * N) where M is word length, N is wordList size
7+
* Space Complexity: O(M^2 * N) for the pattern dictionary
8+
*/
9+
10+
// If beginWord equals endWord, the sequence is just the word itself
11+
if (beginWord === endWord) {
12+
return 1;
13+
}
14+
15+
// If endWord is not in wordList, no valid transformation exists
16+
if (!wordList.includes(endWord)) {
17+
return 0;
18+
}
19+
20+
// Convert wordList to set for O(1) lookup
21+
const wordSet = new Set<string>(wordList);
22+
23+
// Add beginWord to the set if not present
24+
if (!wordSet.has(beginWord)) {
25+
wordSet.add(beginWord);
26+
}
27+
28+
// Build a pattern dictionary to find all words that differ by one letter
29+
// e.g., "hot" -> {"*ot": ["hot"], "h*t": ["hot"], "ho*": ["hot"]}
30+
const patternDict = new Map<string, string[]>();
31+
const wordLen = beginWord.length;
32+
33+
// Create patterns for all words
34+
for (const word of wordSet) {
35+
for (let i = 0; i < wordLen; i++) {
36+
const pattern = word.slice(0, i) + '*' + word.slice(i + 1);
37+
if (!patternDict.has(pattern)) {
38+
patternDict.set(pattern, []);
39+
}
40+
patternDict.get(pattern)!.push(word);
41+
}
42+
}
43+
44+
// BFS to find shortest path
45+
const queue: [string, number][] = [[beginWord, 1]]; // [current_word, level]
46+
const visited = new Set<string>([beginWord]);
47+
48+
while (queue.length > 0) {
49+
const [currentWord, level] = queue.shift()!;
50+
51+
// Try all possible transformations by replacing each character
52+
for (let i = 0; i < wordLen; i++) {
53+
const pattern = currentWord.slice(0, i) + '*' + currentWord.slice(i + 1);
54+
55+
// Get all words matching this pattern
56+
const neighbors = patternDict.get(pattern) || [];
57+
for (const nextWord of neighbors) {
58+
if (nextWord === endWord) {
59+
return level + 1;
60+
}
61+
62+
if (!visited.has(nextWord)) {
63+
visited.add(nextWord);
64+
queue.push([nextWord, level + 1]);
65+
}
66+
}
67+
68+
// Clear the pattern to avoid revisiting in future iterations
69+
patternDict.set(pattern, []);
70+
}
71+
}
72+
73+
return 0;
74+
}
75+
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import pytest
2+
from src.my_project.interviews.top_150_questions_round_22.ex_92_word_ladder import Solution
3+
4+
5+
class TestWordLadder:
6+
def setup_method(self):
7+
self.solution = Solution()
8+
9+
def test_example_1(self):
10+
"""Test Example 1: Standard transformation sequence"""
11+
beginWord = "hit"
12+
endWord = "cog"
13+
wordList = ["hot", "dot", "dog", "lot", "log", "cog"]
14+
15+
result = self.solution.ladderLength(beginWord, endWord, wordList)
16+
assert result == 5, "Should return 5 for the sequence: hit -> hot -> dot -> dog -> cog"
17+
18+
def test_example_2(self):
19+
"""Test Example 2: endWord not in wordList"""
20+
beginWord = "hit"
21+
endWord = "cog"
22+
wordList = ["hot", "dot", "dog", "lot", "log"]
23+
24+
result = self.solution.ladderLength(beginWord, endWord, wordList)
25+
assert result == 0, "Should return 0 when endWord is not in wordList"
26+
27+
def test_single_transformation(self):
28+
"""Test single transformation"""
29+
beginWord = "hot"
30+
endWord = "dot"
31+
wordList = ["hot", "dot"]
32+
33+
result = self.solution.ladderLength(beginWord, endWord, wordList)
34+
assert result == 2, "Should return 2 for direct transformation"
35+
36+
def test_no_transformation_needed(self):
37+
"""Test when begin and end are same"""
38+
beginWord = "hot"
39+
endWord = "hot"
40+
wordList = ["hot"]
41+
42+
result = self.solution.ladderLength(beginWord, endWord, wordList)
43+
assert result == 1, "Should return 1 when beginWord equals endWord"
44+
45+
def test_no_path_exists(self):
46+
"""Test when no valid path exists"""
47+
beginWord = "hit"
48+
endWord = "cog"
49+
wordList = ["hot", "dot", "tog"]
50+
51+
result = self.solution.ladderLength(beginWord, endWord, wordList)
52+
assert result == 0, "Should return 0 when no valid transformation sequence exists"
53+
54+
def test_longer_words(self):
55+
"""Test with longer words"""
56+
beginWord = "teach"
57+
endWord = "place"
58+
wordList = ["teach", "peach", "peace", "place", "reach"]
59+
60+
result = self.solution.ladderLength(beginWord, endWord, wordList)
61+
assert result == 4, "Should return 4 for: teach -> peach -> peace -> place"
62+
63+
def test_multiple_paths(self):
64+
"""Test when multiple paths exist"""
65+
beginWord = "red"
66+
endWord = "tax"
67+
wordList = ["ted", "tex", "red", "tax", "tad", "rex"]
68+
69+
result = self.solution.ladderLength(beginWord, endWord, wordList)
70+
assert result == 4, "Should return 4 for shortest path: red -> ted -> tex -> tax"
71+
72+
def test_empty_word_list(self):
73+
"""Test with empty wordList"""
74+
beginWord = "hit"
75+
endWord = "cog"
76+
wordList = []
77+
78+
result = self.solution.ladderLength(beginWord, endWord, wordList)
79+
assert result == 0, "Should return 0 when wordList is empty"

0 commit comments

Comments
 (0)